Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/39.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何验证是否存在与Rails的关联?_Ruby On Rails_Ruby - Fatal编程技术网

Ruby on rails 如何验证是否存在与Rails的关联?

Ruby on rails 如何验证是否存在与Rails的关联?,ruby-on-rails,ruby,Ruby On Rails,Ruby,假设我有一个基本的Rails应用程序,具有基本的一对多关系,其中每个评论都属于一篇文章: $ rails blog $ cd blog $ script/generate model article name:string $ script/generate model comment article:belongs_to body:text class Article < ActiveRecord::Base has_many :comments end class Commen

假设我有一个基本的Rails应用程序,具有基本的一对多关系,其中每个评论都属于一篇文章:

$ rails blog
$ cd blog
$ script/generate model article name:string
$ script/generate model comment article:belongs_to body:text
class Article < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :article
  validates_presence_of :article_id
end
现在,我添加了创建关联的代码,但我还希望确保在创建注释时,它始终包含一篇文章:

$ rails blog
$ cd blog
$ script/generate model article name:string
$ script/generate model comment article:belongs_to body:text
class Article < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :article
  validates_presence_of :article_id
end
如果您这样做:

>> article = Article.new
=> #<Article id: nil, name: nil, created_at: nil, updated_at: nil>
>> article.comments.build
=> #<Comment id: nil, article_id: nil, body: nil, created_at: nil, updated_at: nil>
>> article.save!
这是有道理的,因为评论还没有页面id

>> article.comments.first.errors.on(:article_id)
=> "can't be blank"
因此,如果我从
comment.rb
中删除
validates\u presence\u of:article\u id
,那么我可以进行保存,但这也允许您创建没有article id的评论。处理此问题的典型方法是什么

更新:根据Nicholas的建议,下面是一个save_的实现,带有_注释,但效果很差:

def save_with_comments
  save_with_comments!
rescue
  false
end

def save_with_comments!
  transaction do
    comments = self.comments.dup
    self.comments = []
    save!
    comments.each do |c|
      c.article = self
      c.save!
    end
  end
  true
end

我不确定是否要为每个一对多关联添加类似的内容。Andy可能是正确的,因为最好避免尝试进行级联保存并使用嵌套属性解决方案。我会把这件事留待一段时间,看看有没有人有其他的建议

你说得对。在进行此验证之前,文章需要一个id。解决这个问题的一种方法是保存文章,如下所示:

>> article = Article.new
=> #<Article id: nil, name: nil, created_at: nil, updated_at: nil>
>> article.save!
=> true
>> article.comments.build
=> #<Comment id: nil, article_id: 2, body: nil, created_at: nil, updated_at: nil>
>> article.save!
=> true
>article=article.new
=> #
>>文章。保存!
=>正确
>>article.comments.build
=> #
>>文章。保存!
=>正确

如果你正在用一种方法或操作创建一篇带有注释的新文章,那么我建议你创建文章并保存它,然后创建注释,但是将整个内容包装在Article.transaction块中,这样您就不会得到任何额外的文章。

您可以验证文章的存在,而不是验证文章id的存在

validates_presence_of :article
然后,当您创建评论时:

article.comments.build :article => article

如果您使用的是Rails2.3,那么您就是在使用新的嵌套模型。我注意到,正如您所指出的,
验证
的存在,或者如果在该字段的迁移中指定了
:null=>false
,也会出现同样的故障

如果您的目的是创建嵌套模型,则应将注释的
接受嵌套属性添加到
article.rb
。这将允许您:

a = Article.new
a.comments_attributes = [{:body => "test"}]
a.save!  # creates a new Article and a new Comment with a body of "test"

您所拥有的是它应该对我起作用的方式,但我发现它与Rails 2.3.2不兼容。在使用您的代码在注释中创建
之前,我调试了一个
,并且没有
文章id
是通过构建提供的(它是零),因此这不起作用。正如Nicholas指出的,您需要先保存文章,或者删除验证。

我已修复此问题,将以下行添加到我的_comment.html.erb中:

如果form.object.NEW\u记录为“新建”?%%>
现在,验证以独立形式工作,也可以以多形式工作。

这失败了,因为Rails 2.3或3.0中没有标识映射。您可以通过将它们缝合在一起手动进行修复

a = Article.new
c = a.comments.build
c.article = a
a.save!

这是可怕的,3.1中的身份映射将帮助修复(除了性能提升)
c.article
a.comments。首先,article
是没有身份映射的不同对象。

我也一直在研究这个主题,下面是我的总结:

OOTB不起作用的根本原因(至少在使用
验证:article
的存在性而不是
验证:article\u id
的存在性时)是rails在内部不使用标识映射,因此它本身不知道
article.comments[x]。article==article

我找到了三种变通方法,只需稍加努力即可实现:

  • 在创建评论之前保存文章(rails会自动将保存期间生成的文章id传递给每个新创建的评论;请参阅Nicholas Hubbard的回复)
  • 在创建评论后,明确地在评论上设置文章(见W.Andrew Loe III的回复)
  • 使用以下各项的逆函数:
    class Article < ActiveRecord::Base
      has_many :comments, :inverse_of => :article
    end
    
    类文章:文章
    结束

  • 本文中还提到了最后一个解决方案,但由于缺少身份映射,它似乎是rails的快速解决方案。在我看来,这也是三个答案中最不具侵扰性的一个。

    因为我只能对自己的答案发表评论。Daniel是正确的,您可以使用validates来代替article_id来验证文章的存在,但是如果您使用article.comments.build,由于rails使用的构建器,此操作仍然无法运行。是的,我认为问题在于,还没有文章id,因为文章已保存,因为此操作在验证期间运行。我认为操作顺序是:1。对第2条有效。验证所有注释3。保存第4条。保存注释,使步骤2失败,因为还没有id。验证:article的存在与验证:article的存在是否有区别?对我来说,这两种方法都很好(Rails 3)。一篇尚未保存的文章可能仍然存在,但在整个保存事务完成之前缺少id。相反的方法完美地回答了这个问题。与其他解决方案不同,它可以很好地与其他Rails习惯用法(如accepts_nested_attributes_for)配合使用。这对我来说非常有效,使用了带有嵌套属性的深度嵌套表单。通过首先保存父模型,创建子对象并在父\u id上进行验证意味着我可以保持验证:)设置反向\u也对我有效,但我必须将状态验证从\u id更改为仅使其工作。是的。。这是当需要存在关联时(即使尚未保存关联)的答案