在 Rails 中,关联的 objects 是如何 up-to-date 的?
In Rails, how does one associated objects are up-to-date?
考虑:
class Parent < ActiveRecord::Base
has_many :blue_children
has_many :red_children
end
class BlueChild < ActiveRecord::Base
belongs_to :parent
end
class RedChild < ActiveRecord::Base
belongs_to :parent
validate :parent_cannot_have_blue_children
def parent_cannot_have_blue_children
unless parent.blue_children.empty?
errors.add(:parent, 'has blue children')
end
end
end
对于这样的代码:
def test
p = Parent.create!
# Much time passes, during which, perhaps, some far-off process adds
# a blue child to p.
p.red_children.create!
end
存在验证者看到 out-of-date 版本 parent 的风险。特别是,即使验证器中似乎没有蓝色 children,也可能有一个。我检查了 SQL 日志以确认没有查询重新加载 parent 或来自验证器的 blue_children
关联。
我可以想出几种方法来解决这个问题:
- 在数据库本身中保留一个计数器,计算
Parent
中蓝色 children 的数量,当添加 children 时自动 incremented/decremented,并检查柜台而不是看协会本身。这可行,但代价是模型更复杂,数据库存储更多。
- 将
before_validation
挂钩添加到 RedChild
以重新加载 Parent
。但是,如果将 child object 重置未决更改保存到 parent. ,调用者会感到非常惊讶
- 坚持要保存一个
RedChild
的调用者创建一个交易,在交易中重新加载Parent
,然后保存child,这样验证器就可以保证up-to-date。这可行,但很麻烦,而且似乎违反了 child object. 的封装
目前,我倾向于在数据库中维护一个计数器。有没有更好的方法?
您可以在验证中使用 exists?
:它将触发一个新的 SQL 请求来检查蓝色 children 是否存在:
class RedChild < ActiveRecord::Base
belongs_to :parent
validate :parent_cannot_have_blue_children
def parent_cannot_have_blue_children
if BlueChild.exists?(parent: self.parent)
errors.add(:parent, 'has blue children')
end
end
end
这样验证总是最新的。
考虑:
class Parent < ActiveRecord::Base
has_many :blue_children
has_many :red_children
end
class BlueChild < ActiveRecord::Base
belongs_to :parent
end
class RedChild < ActiveRecord::Base
belongs_to :parent
validate :parent_cannot_have_blue_children
def parent_cannot_have_blue_children
unless parent.blue_children.empty?
errors.add(:parent, 'has blue children')
end
end
end
对于这样的代码:
def test
p = Parent.create!
# Much time passes, during which, perhaps, some far-off process adds
# a blue child to p.
p.red_children.create!
end
存在验证者看到 out-of-date 版本 parent 的风险。特别是,即使验证器中似乎没有蓝色 children,也可能有一个。我检查了 SQL 日志以确认没有查询重新加载 parent 或来自验证器的 blue_children
关联。
我可以想出几种方法来解决这个问题:
- 在数据库本身中保留一个计数器,计算
Parent
中蓝色 children 的数量,当添加 children 时自动 incremented/decremented,并检查柜台而不是看协会本身。这可行,但代价是模型更复杂,数据库存储更多。 - 将
before_validation
挂钩添加到RedChild
以重新加载Parent
。但是,如果将 child object 重置未决更改保存到 parent. ,调用者会感到非常惊讶
- 坚持要保存一个
RedChild
的调用者创建一个交易,在交易中重新加载Parent
,然后保存child,这样验证器就可以保证up-to-date。这可行,但很麻烦,而且似乎违反了 child object. 的封装
目前,我倾向于在数据库中维护一个计数器。有没有更好的方法?
您可以在验证中使用 exists?
:它将触发一个新的 SQL 请求来检查蓝色 children 是否存在:
class RedChild < ActiveRecord::Base
belongs_to :parent
validate :parent_cannot_have_blue_children
def parent_cannot_have_blue_children
if BlueChild.exists?(parent: self.parent)
errors.add(:parent, 'has blue children')
end
end
end
这样验证总是最新的。