class A < ActiveRecord::Base
has_many :bs
has_many :cs , through: :bs
end
class B < ActiveRecord::Base
belongs_to :a
has_many :cs
end
class C < ActiveRecord::Base
belongs_to :b
end
三个 model 的关系如上所示,如果我现在想要保证 C 中的一个属性(比如 c.name)在所关联的 A 中是唯一的。这样的 uniq 怎么实现呢?是应该去用 before_create 去实现吗? 比如
a = A.create
b = B.create
a.bs << b
b.cs << C.create(name: "test") #通过
b.cs << C.create(name: "test") #Error
楼上正解,另外希望你belongs_to :cs
修正一下
validates :name, uniqueness: { scope: :b_id,message: "name should not repeat per B object" }
#2 楼 @lyfi2003 这个也不是我所需要的,我要保证的时在一个 A 的 record(例如 a),他所关联的所有 C 的 record 的 name 属性是唯一的。这个只能保证一个 b 所关联的 c 的所有 name 属性的值是唯一的。 也就是下面这种代码的效果。如果采用你的这种验证方式的话,下面的代码是能够通过的
a = A.create
b1 = B.create
b2 = B.create
a.bs << b1
a.bs << b2
b1.cs << C.create(name: "test") #通过
b2.cs << C.create(name: "test") #Error
类似的问题还在 find_or_create_by
Please note this method is not atomic, it runs first a SELECT, and if there are no results an INSERT is attempted. If there are other threads or processes there is a race condition between both calls and it could be the case that you end up with two similar records.
http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-find_or_create_by
Using this validation method in conjunction with ActiveRecord::Validations#save does not guarantee the absence of duplicate record insertions, because uniqueness checks on the application level are inherently prone to race conditions.
validate do
if self.b.a.cs.where(name: self.name).first
errors.add(:name, 'babala...')
end
end
这种限制在并发的环境下可能出现限制失效的情况,比如你开了多进程实例或者多线程。
User 1 | User 2
------------------------------------+--------------------------------------
# User 1 checks whether there's |
# already a comment with the title |
# 'My Post'. This is not the case. |
SELECT * FROM comments |
WHERE title = 'My Post' |
|
| # User 2 does the same thing and also
| # infers that their title is unique.
| SELECT * FROM comments
| WHERE title = 'My Post'
|
# User 1 inserts their comment. |
INSERT INTO comments |
(title, content) VALUES |
('My Post', 'hi!') |
|
| # User 2 does the same thing.
| INSERT INTO comments
| (title, content) VALUES
| ('My Post', 'hello!')
|
| # ^^^^^^
| # Boom! We now have a duplicate
| # title!
这个例子形象的说明了一切