Ruby on rails 循环一对一模型保存调用,两边都有状态验证
假设存在一个Ruby on rails 循环一对一模型保存调用,两边都有状态验证,ruby-on-rails,validation,factory-bot,Ruby On Rails,Validation,Factory Bot,假设存在一个Foo和Bar模型,具有一对一关系和相互存在验证: class Foo < ActiveRecord::Base has_one :foo_bar has_one :bar, through: :foo_bar, inverse_of: :foo validates :bar, presence: true end class FooBar < ActiveRecord::Base belongs_to :foo belongs_to :bar e
Foo
和Bar
模型,具有一对一
关系和相互存在验证:
class Foo < ActiveRecord::Base
has_one :foo_bar
has_one :bar, through: :foo_bar, inverse_of: :foo
validates :bar, presence: true
end
class FooBar < ActiveRecord::Base
belongs_to :foo
belongs_to :bar
end
class Bar < ActiveRecord::Base
has_one :foo_bar
has_one :foo, through: :foo_bar, inverse_of: :bar
validates :foo, presence: true
end
当我试图用FactoryGirl.create(:Foo)
创建Foo
或Bar
的实例时,我得到了SystemStackError:堆栈级别太深
原因是:
foo
对象时,它会查看相关的条
bar
时,它会查看foo
(尚未保存)和
决定拯救它autosave:false
,如:
class Bar
has_one :foo, through: :foo_bar, inverse_of: :bar, autosave: false
end
这允许创建Foo
,但阻止create(:bar)
,因为Foo
关联将不会被保存,从而导致无效的bar
记录(由于验证)
如何修复它,使
foo
和bar
工厂都有效?我认为验证:foo,presence:true
最终使用验证相关的
文档状态:不要在关联的两端使用关联的validates\u。他们会在无限循环中互相呼叫。
基本上,一个人必须是一个追随者。。。也许您可以解释一下您的用例,并获得一些数据模型反馈?我同意模型结构似乎有问题。最好的解决方案可能是通过不同的关联实现您想要的。然而,如果这不是一个选择,我会抛出一个想法,可能会让你的地方
您可以覆盖autosave并自己检查是否存在。您仍然需要一个依赖于另一个,但您可以在您的Foo模型中执行以下操作:
def autosave_associated_records_for_bar
#validate data
#save bar
#probably need to save ids on foobar
end
注意:执行此操作时应小心,并真正确保了解效果(验证程序可能无法运行等)
您可以在以下源代码中查看有关AutosaveAssociation的更多信息:
也许里面有些东西会有帮助。这是一个概念问题。想想看,你在国外,你的文件丢了。你去你的大使馆,他们想看你的机票来签发新护照。你去航空公司,他们要你的护照签发一份机票复印件。这是一个僵局,一个鸡和蛋的问题
解决这个问题的唯一办法是重新定义它。您可以决定是否要验证关系,但对于至少一个方向,您将仅在创建关系后进行验证
class Foo < ActiveRecord::Base
has_one :foo_bar
has_one :bar, through: :foo_bar, inverse_of: :foo
validates :bar, presence: true, on: :update
end
class Foo
因此,在我们的例子中,航空公司仍然不会给你没有护照的机票,但是大使馆会给你没有机票的护照。此外,如果您已经持有护照并且出于任何原因前往大使馆,他们会要求查看机票以进行确认。您能解释一下为什么您会使用这种关系而不是是否有一个&属于?使用一个额外的模型而不是一个额外的字段似乎很复杂。@TheChamp这听起来很合理,但我仍然对解决原始问题感兴趣。
class Foo < ActiveRecord::Base
has_one :foo_bar
has_one :bar, through: :foo_bar, inverse_of: :foo
validates :bar, presence: true, on: :update
end