2016-09-21 51 views
13

我一直被这个问题困住了一段时间,并且对自己如何嵌套模型和验证如何协同工作充分感到困惑。Rails:防止创建父模型并显示子模型验证错误

在下面的代码中,如果验证子模型(内容)失败,我的目标是创建父模型(图像或视频)失败。目前,父模型正在保存,而子模型不存在,并且验证错误未被听到。如果没有验证错误,那么一切都按预期工作。

#Image.rb 
has_one  :content, 
as:   :contentable, 
inverse_of: :contentable, 
dependent: :destroy 

#Video.rb 
has_one  :content, 
as:   :contentable, 
inverse_of: :contentable, 
dependent: :destroy 

#Content.rb 
belongs_to :contentable, 
inverse_of: :content, 
polymorphic: true 

validate  :all_good? 

def all_good? 
    errors.add(:base, "Nope!") 
    return false 
end 

任何潜在客户或见解都非常感谢!

+0

您正在使用哪种版本的导轨? – dnsh

+0

@Dinesh Rails 4.2.6 – geoboy

+0

为什么你要像这样设置它 - 除非你提出最终目标,否则“推荐方法”是不可行的 - 分离这样的项目的原因究竟是什么 - 模型/模式看起来像你的应用程序需要这种分离? – MageeWorld

回答

0

您需要在自定义验证中引发异常。 这样做

before_save :ensure_all_good 

def ensure_all_good 
try saving stuff to chile 
failed? raise nope 
end 
+0

有趣的想法。我不应该仅仅通过验证和错误对象就能做到这一点,但更传统的导轨方式呢? – geoboy

+0

我不会实现逻辑来更新我的验证中的孩子。因为这会导致误导。因此,为什么我宁愿使用before_save来更新,并在那里处理它。 你总是可以把这两个请求放在一个transactiwould不会被承诺。 –

+0

@geoboy我刚刚遇到类似的问题,来自子模型的错误不会传递给父模型。在你的情况下,因为验证是在内容模型中。父模型视频和图像将无法看到来自内容的错误。 你可能想看看下面的链接,建议如何将错误从孩子模型合​​并到父母中 http://stackoverflow.com/questions/2680016/ruby-on-rails-how-to-get-error-messages -from-a-resource-displayed- –

4

Rails有一个特殊的验证称为validates_associated,确保了相关的结果是有效的。如果关联的记录无效,则父记录也将无效,并且该关联的错误将被添加到其错误列表中。

在这两个图像和视频类添加以下内容:

validates_associated :content 

现在,如果content协会是无效的视频或图像不会被保存。

video = Video.new 
video.content = Content.new 
video.save #=> false 
video.valid? #=> false 
video.errors #=> [:content => "is invalid"] 
+0

感谢您抽出时间回复。不幸的是,这是行不通的。它仍然继续保存记录(如果我插入'validates_presence_of:content',那么它会说'内容不能为空]。嵌套是否会导致这种情况? 另外,从文档:“注意:如果关联尚未分配,此验证将不会失败。如果要确保关联既存在并且保证有效,还需要使用validates_presence_of” – geoboy

4

简答

添加到图像和视频模式:

accepts_nested_attributes_for :content

的证明

我很肯定我知道这个问题的答案,但不知道它是否与多态联系起作用离子(我以前没有用过),所以我设置了一个小测试。

创建模型的方式与您的设置相同,但具有名称属性以及可用于验证失败的验证。

class Image < ActiveRecord::Base 
    has_one  :content, 
       as:   :contentable, 
       inverse_of: :contentable, 
       dependent: :destroy 

    validates_length_of :name, maximum: 10 
end 

class Content < ActiveRecord::Base 
    belongs_to :contentable, 
       inverse_of: :content, 
       polymorphic: true 

    validates_length_of :name, maximum: 10 
end 

下设置的迁移,像这样:

class CreateImages < ActiveRecord::Migration 
    def change 
    create_table :images do |t| 
     t.string :name 

     t.timestamps null: false 
    end 
    end 
end 


class CreateContents < ActiveRecord::Migration 
    def change 
    create_table :contents do |t| 
     t.string :name 
     t.references :contentable, polymorphic: true, index: true 

     t.timestamps null: false 
    end 
    end 
end 

下一页写一个RSpec测试父不会被保存,如果孩子不能保存和验证错误perculate起来。

it 'should not save image if content is invalid' do 
    image = Image.new() 
    image.name = 'this is ok' 
    expect(image).to be_valid 

    content = Content.new() 
    content.name = 'a string that should fail validation' 
    image.content = content 

    expect(image).to_not be_valid 
    image.save 

    expect(image).to_not be_persisted 
    expect(content).to_not be_persisted 

    expect(image.errors.count).to eq(1) 
    expect(image.content.errors[:name][0]).to include('is too long') 
    end 

冉测试,果然失败。

下一页添加以下行到图像(视频)

accepts_nested_attributes_for :content 

测试现在通 - 即,如果孩子未通过验证的父母也将无法通过验证,将无法保存。