2015-02-05 101 views
2

打电话给定有一个FooBar型号one-to-one关系和彼此的存在验证:通知一到一个模型保存存在验证两侧

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.define do 
    factory :foo do 
    foo_bar 
    bar { |foo| build(:bar, foo_bar: foo_bar, foo: foo) } 
    end 

    factory :bar do 
    foo_bar 
    foo { |bar| build(:foo, foo_bar: foo_bar, bar: bar) } 
    end 

    factory :foo_bar do 
    end 
end 

当我尝试创建FooBarFactoryGirl.create(:foo)的实例时,我得到SystemStackError: stack level too deep

这样做的原因是:

  1. 当保存foo对象看起来在相关bar
  2. A-HA! bar不会被保存,我们需要保存它首先
  3. 虽然节省bar它着眼于foo(其中尚未保存)和 决定将其保存
  4. 等它试图挽救对方这会导致无穷环

一个解决方案是对关联的像的端部之一添加autosave: false

class Bar 
    has_one :foo, through: :foo_bar, inverse_of: :bar, autosave: false 
end 

这允许创建Foo但PR事件create(:bar),因为foo协会将不会被保存,这将导致无效的Bar记录(由于验证)。

如何修复,以便foobar工厂都有效?

+0

你能否解释为什么你会使用这种关系而不是'has_one'&'belongs_to'?使用一个额外的模型,而不是一个额外的领域似乎很复杂。 – 2015-02-08 11:33:34

+0

@TheChamp这听起来很合理,但我仍然对解决原始问题感兴趣。 – freemanoid 2015-02-09 07:19:23

回答

0

我同意模型结构似乎关闭。最好的解决方案是可能通过不同的关联实现你想要的。但是,如果这不是一个选项,我会抛出一个想法,可能会让你在某个地方。

您可以覆盖自动保存并检查自己的存在。您仍然需要有一个依赖于其他的,但你可以做这样的事情在你的Foo型号:

def autosave_associated_records_for_bar 
    #validate data 
    #save bar 
    #probably need to save ids on foobar 
end 

注:这样做的,真正确保你理解的影响时,您应该谨慎(验证器不能运行等)

可以在这里的源代码中检查出AutosaveAssociation:https://github.com/rails/rails/blob/master/activerecord/lib/active_record/autosave_association.rb

也许东西在里面会有所帮助。

1

这是一个概念性问题。考虑一下 - 你在国外,你丢失了你的文件。你去你的大使馆,他们想看你的机票签发新护照。你去了航空公司,他们想要你的护照签发票的副本。这是一个僵局,一个鸡与鸡蛋的问题。

解决问题的唯一方法是重新定义它。您可以决定是否要验证关系,但对于至少一个指示,只有在创建后才能进行验证。

class Foo < ActiveRecord::Base 
    has_one :foo_bar 
    has_one :bar, through: :foo_bar, inverse_of: :foo 

    validates :bar, presence: true, on: :update 
end 

所以,在我们的例子中,航空公司仍然不会发给你你的票没有护照,但使馆会给你的护照没有门票。此外,如果您已经有护照并出于任何原因前往大使馆,他们会要求查看门票以确认。

+0

不错的比喻,谢谢! :) – freemanoid 2015-02-12 02:50:46

相关问题