【发布时间】:2010-11-21 20:31:04
【问题描述】:
我的 Rails 应用程序中的用户和角色之间存在标准的多对多关系:
class User < ActiveRecord::Base
has_many :user_roles
has_many :roles, :through => :user_roles
end
我想确保一个用户只能被分配一次任何角色。任何插入重复项的尝试都应忽略该请求,而不是引发错误或导致验证失败。我真正想要表示的是一个“集合”,其中插入集合中已经存在的元素没有任何效果。 {1,2,3} U {1} = {1,2,3},而不是 {1,1,2,3}。
我意识到我可以这样做:
user.roles << role unless user.roles.include?(role)
或者通过创建一个包装方法(例如add_to_roles(role)),但我希望有一些惯用的方式通过关联使其自动化,以便我可以编写:
user.roles << role # automatically checks roles.include?
它只是为我工作。这样,我就不必记住检查重复或使用自定义方法。我缺少的框架中有什么东西吗?我首先认为 has_many 的 :uniq 选项可以做到这一点,但它基本上只是“选择不同的”。
有没有办法以声明的方式做到这一点?如果没有,也许通过使用关联扩展?
以下是默认行为如何失败的示例:
>> u = User.create
用户创建 (0.6ms) INSERT INTO "users" ("name") VALUES(NULL)
=> #
>> u.roles
角色加载 (0.5ms) SELECT * FROM "roles" LIMIT 1
UserRole Create (0.5ms) INSERT INTO "user_roles" ("role_id", "user_id") VALUES(1, 3)
角色加载 (0.4ms) SELECT "roles".* FROM "roles" INNER JOIN "user_roles" ON "roles".id = "user_roles".role_id WHERE (("user_roles".user_id = 3))
=> [#]
>> u.roles
角色加载 (0.4ms) SELECT * FROM "roles" LIMIT 1
UserRole Create (0.5ms) INSERT INTO "user_roles" ("role_id", "user_id") VALUES(1, 3)
=> [#, #]
【问题讨论】:
标签: ruby-on-rails activerecord associations idioms