Rails idiom to avoid duplicates in has_many :through

前端 未结 8 1838
难免孤独
难免孤独 2020-12-07 12:09

I have a standard many-to-many relationship between users and roles in my Rails app:

class User < ActiveRecord::Base
  has_many :user_roles
  has_many :ro         


        
相关标签:
8条回答
  • 2020-12-07 12:49

    i think the proper validation rule is in your users_roles join model:

    validates_uniqueness_of :user_id, :scope => [:role_id]
    
    0 讨论(0)
  • 2020-12-07 12:57

    Perhaps it is possible to create the validation rule

    validates_uniqueness_of :user_roles
    

    then catch the validation exception and carry on gracefully. However, this feels really hacky and is very inelegant, if even possible.

    0 讨论(0)
  • 2020-12-07 13:00

    As long as the appended role is an ActiveRecord object, what you are doing:

    user.roles << role
    

    Should de-duplicate automatically for :has_many associations.

    For has_many :through, try:

    class User
      has_many :roles, :through => :user_roles do
        def <<(new_item)
          super( Array(new_item) - proxy_association.owner.roles )
        end
      end
    end
    

    if super doesn't work, you may need to set up an alias_method_chain.

    0 讨论(0)
  • 2020-12-07 13:00

    You can use a combination of validates_uniqueness_of and overriding << in the main model, though this will also catch any other validation errors in the join model.

    validates_uniqueness_of :user_id, :scope => [:role_id]
    
    class User
      has_many :roles, :through => :user_roles do
        def <<(*items)
          super(items) rescue ActiveRecord::RecordInvalid
        end
      end
    end
    
    0 讨论(0)
  • 2020-12-07 13:01

    I think you want to do something like:

    user.roles.find_or_create_by(role_id: role.id) # saves association to database
    user.roles.find_or_initialize_by(role_id: role.id) # builds association to be saved later
    
    0 讨论(0)
  • 2020-12-07 13:01

    This will create only one association in the database even if called multiple times Refer rails guide.

    user.roles=[Role.first] 
    
    0 讨论(0)
提交回复
热议问题