Validation 如何避免在自引用模型中由于不引用自身和不重复引用而更新记录
我有自参考模型:Validation 如何避免在自引用模型中由于不引用自身和不重复引用而更新记录,validation,ruby-on-rails-4,model,self-reference,rails-models,Validation,Ruby On Rails 4,Model,Self Reference,Rails Models,我有自参考模型: class Component < ActiveRecord::Base has_and_belongs_to_many :allergens has_many :cqnames, as: :cqnable has_many :inclusions has_many :ingredients, :through => :inclusions accepts_nested_attributes_for :cqnames, allow_destroy
class Component < ActiveRecord::Base
has_and_belongs_to_many :allergens
has_many :cqnames, as: :cqnable
has_many :inclusions
has_many :ingredients, :through => :inclusions
accepts_nested_attributes_for :cqnames, allow_destroy: true
accepts_nested_attributes_for :ingredients
accepts_nested_attributes_for :inclusions, allow_destroy: true
translates :name, :description
validates :name, presence: true, uniqueness: true
def self.get_children(ing)
@tree ||= []
if ing.ingredients.nil?
return @tree
else
@tree << ing.ingredients
get_children(ing.ingredients)
end
end
end
我必须避免自引用同一记录,也要避免在更新相关记录时引用已引用的记录
在验证之前进行试验…:
class Component < ActiveRecord::Base
before_validation :hokus
has_and_belongs_to_many :allergens
has_many :cqnames, as: :cqnable
has_many :inclusions
has_many :ingredients, :through => :inclusions
has_many :inverse_inclusions, :class_name => "Inclusion", :foreign_key => "ingredient_id"
has_many :composites, :through => :inverse_inclusions, :source => :component
accepts_nested_attributes_for :cqnames, allow_destroy: true
accepts_nested_attributes_for :ingredients
accepts_nested_attributes_for :inclusions, allow_destroy: true
translates :name, :description
validates :name, presence: true, uniqueness: true
require 'set'
def self.pokus(ing)
avoid = Set.new([self])
q = true
if ing.ingredients.present?
ing.ingredients.each do |record|
q = false if avoid.include? record
end
end
q
end
def hokus
Component.pokus(self)
end
end
我觉得这有点乱。但我会给你一个指针,告诉你如何建立一个没有重复项的列表
require 'set'
def self.get_children(ing)
tree = Set.new
avoid = Set.new([self])
recursive = lambda {|recs|
recs.ingredients.each do |record|
pass = false
if avoid.include? record
pass = true
else
tree << record
avoid << record
end
recursive.call(record.ingredients) unless pass
end
}
recursive.call(ing.ingredients)
tree.to_a
end
我已经做了一些类似这样的递归工作,所以我相信这会实现您希望的。虽然我还没有测试这段代码
如果你想看看我写的深度优先记录复制方法,你可以在我的gem中看到。我在我构建的集合上使用了一个变体,它与我在这里演示的避免集合基本相同。我在我的博客文章中解释了这一点,如果你想要一个更简单的版本来完成这项工作,那么这就可以了
require 'set'
def self.get_children(ing)
tree = Set.new
recursive = lambda {|recs|
recs.ingredients.each do |record|
recursive.call(record.ingredients) if tree.add?(record)
end
}
recursive.call(ing.ingredients)
tree.to_a
end
非常感谢你的回复,丹。我是一个绝对的编码新手,我无法想象你的代码会做什么。我研究了很多,包括你的博客文章和PBT。通常,在我的自引用模型类中,我必须避免任何深度的循环引用。我可以想象算法-BMO适当的逻辑可以在保存/更新之前在模型级别实现,或者在控制器表单级别实现,以避免在相关的选择框中提供不适当的选择,可能两者都有,但我的编码技能仍然非常差,我不知道如何编码它…Set是一个独特的列表。它类似于数组,但只保留每个对象中的一个。因此,它将为您完成大部分工作。你设计东西的方式看起来很难维护。如果你能避免的话,我会避免使用has_和would_to_many。你能保持的越简单,你的生活就会越好。你要做的不是一个新手。你可能有兴趣研究一个现有的gem,它将为你提供层次结构方面的东西。这个自引用模型实际上是-有很多:成分,:通过=>:内含物-而不是HABTM。这不是毫无目的的设计。所有这些协会都运作良好。我知道这有点复杂。我已经找到了,但BMO不是我要找的。我需要的正是自我参照所拥有的:通过联想,正如我所写的,它非常有效。我所要做的就是避免这种循环的自我参照。但这超出了我目前的技能。多年来,我一直在准备和分析我们应用程序的设计,但没有编码。在过去的几年里,我通常在Drupal6/7上构建它,这也是一个复杂的平台,但它有很多限制,我决定通过学习编写RubyRails应用程序来打破这些限制。如果您熟悉c9.io IDE,我可以授予您访问我的dev env的权限,以便更好地了解我的工作内容。在irb/rails控制台中对各个部分进行实验,看看它们是如何工作的。集合。添加?方法是您想要的关键。看到我的另一个答案了吗。