ruby-on-railsrolify

Rolify make association to a user with a specific role


I want to make an association where a user has many deals and a deal belongs to a user as well as another with a role ('associate').

I am using the rolify gem to do this.

Like this:

# user.rb

has_many :deals
# deal.rb

belongs_to :user
belongs_to :associate # User with role 'associate or admin'

The first belongs to could be whatever user, doesn't matter if the user is any role it should still work, the second belongs to however should most definitely be an associate or an admin

Do you think I should use rolify for this? or should I not and just make a different model for each role?

Update

My current solution won't work because the user as an associate would need two associations, the has many deals and the has_many :client_deals. I'm not sure in the naming still.

Update 2

Max's solution works great!


Solution

  • This is not where you want to use Rolify's tables. Rolify creates a one-to-one assocation between roles and resources through the roles tables. Roles then have a many-to-many assocation through the users_roles table to users.

    Which means it works great for cases where the association is one-to-many or many-to-many but Rolify really can't guarantee that there will ever only be one user with a particular role due to the lack of database constraints.

    Diagram

    Even if you add validations or other application level constraints that still leaves the potential for race conditions that could be a double click away.

    Instead you want to just create separate one-to-one assocations:

    class Deal < ApplicationRecord
      belongs_to :creator, 
        class_name: 'User',
        inverse_of: :created_deals
      belongs_to :associate, 
        class_name: 'User',
        inverse_of: :deals_as_associate
    
      validates :must_have_associate_role!
    
      private
      def must_have_associate_role!
        # this could just as well be two separate roles...
        errors.add(:associate, '^ user must be an associate!') unless associate.has_role?(:associate)
      end
    end
    
    class User < ApplicationRecord
      has_many :created_deals, 
        class_name: 'Deal'
        foreign_key: :creator_id,
        inverse_of: :creator
      has_many :deals_as_associate, 
        class_name: 'Deal'
        foreign_key: :associate_id,
        inverse_of: :associate
    end
    

    Two models can really have an unlimited number of associations between them as long as the name of each assocation is unique and you configure it correctly with the class_name and foreign_key options.

    Since this uses a single foreign key this means that ere can ever only be one and you're safeguarded against race conditions.