确保has_many:through关联在创建时是唯一的 [英] Make sure has_many :through association is unique on creation

查看:78
本文介绍了确保has_many:through关联在创建时是唯一的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果在记录创建时保存has_many:through关联,那么如何确保该关联具有唯一的对象。唯一性由一组自定义属性定义。



考虑:

 类用户< ActiveRecord :: Base 
has_many:user_roles
has_many:roles通过::user_roles

before_validation:ensure_unique_roles

private
def sure_unique_roles
#我认为以下方法会起作用:
self.roles = self.roles.to_a.uniq {| r | #{r.project_id}-#{r.role_id}}
#但是上面的结果重复,而且有点奇怪,因为它通过ActiveRecord赋值运算符进行关联(这很可能是原因它不能正常工作)

#我也尝试过:
self.user_roles = []
self.roles = self.roles.to_a.uniq {| r | #{r.project_id}-#{r.role_id}}

#但这也很奇怪,因为它清除了可能具有辅助数据的用户角色
结尾
end

验证user_roles的最佳方法是什么,角色基于唯一性是唯一的

解决方案

做到这一点的最佳方法(尤其是在使用关系数据库的情况下)是 user_roles 上的唯一多列索引。



add_index:user_roles,[:user_id ,:role_id],唯一:true



然后在角色添加失败时正常处理:

 类用户< ActiveRecord :: Base 
def try_add_unique_role(role)
self.roles<<角色
抢救WhateverYourDbUniqueIndexException是
#以某种方式优雅地处理
#(返回false,引发您自己的应用程序异常等)
end
end

关系数据库旨在保证引用完整性,因此可以使用它。任何仅适用于红宝石/铁路的解决方案都将具有竞争条件和/或实际上效率低下。只需检查以下内容即可:

  already_has_role = UserRole.exists?(用户:用户,角色:前瞻性角色_additions)

不过,当您尝试保留角色添加时,仍然必须处理潜在的异常。


If you are saving a has_many :through association at record creation time, how can you make sure the association has unique objects. Unique is defined by a custom set of attributes.

Considering:

 class User < ActiveRecord::Base
   has_many :user_roles
   has_many :roles, through: :user_roles

   before_validation :ensure_unique_roles

   private
   def ensure_unique_roles
      # I thought the following would work:
      self.roles = self.roles.to_a.uniq{|r| "#{r.project_id}-#{r.role_id}" }
      # but the above results in duplicate, and is also kind of wonky because it goes through ActiveRecord assignment operator for an association (which is likely the cause of it not working correctly)

     # I tried also:
     self.user_roles = []
    self.roles = self.roles.to_a.uniq{|r| "#{r.project_id}-#{r.role_id}" }

     # but this is also wonky because it clears out the user roles which may have auxiliary data associated with them
   end
 end

What is the best way to validate the user_roles and roles are unique based on arbitrary conditions on an association?

解决方案

The best way to do this, especially if you're using a relational db, is to create a unique multi-column index on user_roles.

add_index :user_roles, [:user_id, :role_id], unique: true

And then gracefully handle when the role addition fails:

class User < ActiveRecord::Base
  def try_add_unique_role(role)
    self.roles << role
  rescue WhateverYourDbUniqueIndexExceptionIs
    # handle gracefully somehow
    # (return false, raise your own application exception, etc, etc)
  end
end

Relational DBs are designed to guarantee referential integrity, so use it for exactly that. Any ruby/rails-only solution will have race conditions and/or be really inefficient.

If you want to provide user-friendly messaging and check "just in case", just go ahead and check:

already_has_role = UserRole.exists?(user: user, role: prospective_role_additions)

You'll still have to handle the potential exception when you try to persist role addition, though.

这篇关于确保has_many:through关联在创建时是唯一的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆