← Back to Upcase

"Virtual associations" in Rails

(rpassis) #1

Hi all, first post here so please be nice :smile:

I’m looking for some guidance on how to implement what I am referring to as “virtual associations” into my model in rails.

I’ll preface this with the disclaimer that I have considered going down the real associations path (HABTM) but as far as I can see this would conflict with concepts that I already have implemented.

I currently have a Project model which can be associated with User objects via roles.
As an example, a sample_project may have many site_managers, construction_managers and project_managers.
A site_manager can also be a project_manager for the same or different projects (rules out single table inheritance).

With the Rolify gem this is fairly straightforward to implement. I can assign any of the roles above to a particular user in a s pecific project with sample_user.add_role(:site_manager, sample_project).

One of my goals is to be able to create a form where I can setup a new project, and assign users to roles from using a multi-select list. So as an example, my form would have the following input to assign selected users as site manager for the new project:

= f.input :site_managers, collection: User.all, input_html: { multiple: true } (Formtastic DSL)

This is where things get slightly complicated. I have managed to implement a custom getter/setter for the site_maanagers attribute where I can take a hash of user_ids passed by the form and fetch/update the appropriate records as needed.

However this implementation is far from being similar to that of a real association, where I could do things like adding a single user to the site_managers with sample_project.site_managers << sample_user.

At the moment I am also unable to set the array of site_managers using user instances. My custom setter only takes user_ids as the argument which is a bit cumbersome and not very intuitive when used outside of a form submission implementation. I can easily work around this by checking types inside the setter method but it feel hackery and not very Rails like.

I’ve tried ditching the whole custom getter/setter and going with a HABTM implementation that uses a join table to manage all these records but I am concerned that this won’t scale well if/when we need to add more roles to the project (each role adds an extra column to the join table). It also ends up feeling like I am duplicating functionality/concepts that are already offered with Rolify so in some places I am checking for roles in a join table and in using Rolify in others (i.e. if a user is an admin or has access to a certain resource).

Is there something else I may have overlooked or this the only way of getting this done?

Thanks and I look forward to hearing some of your opinions.

Rog

0 Likes