pjb*_*jb3 18 ruby ruby-on-rails
假设我有一个基本的Rails应用程序,其基本的一对多关系,其中每个评论都属于一篇文章:
$ rails blog
$ cd blog
$ script/generate model article name:string
$ script/generate model comment article:belongs_to body:text
Run Code Online (Sandbox Code Playgroud)
现在我添加代码来创建关联,但我也想确保在创建注释时,它总是有一篇文章:
class Article < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :article
validates_presence_of :article_id
end
Run Code Online (Sandbox Code Playgroud)
现在让我们说我想创建一篇带有评论的文章:
$ rake db:migrate
$ script/console
Run Code Online (Sandbox Code Playgroud)
如果你这样做:
>> 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!
Run Code Online (Sandbox Code Playgroud)
你会收到这个错误:
ActiveRecord::RecordInvalid: Validation failed: Comments is invalid
Run Code Online (Sandbox Code Playgroud)
这是有道理的,因为评论还没有page_id.
>> article.comments.first.errors.on(:article_id)
=> "can't be blank"
Run Code Online (Sandbox Code Playgroud)
因此,如果我删除了validates_presence_of :article_idfrom comment.rb,那么我可以执行保存,但这也可以让您创建没有文章ID的注释.处理此问题的典型方法是什么?
更新:根据尼古拉斯的建议,这里有一个save_with_comments的实现,但是很难看:
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
Run Code Online (Sandbox Code Playgroud)
我不确定是否要为每个一对多关联添加这样的内容.Andy可能是正确的,因为最好避免尝试进行级联保存并使用嵌套属性解决方案.我会暂时搁置一下,看看是否有人有任何其他建议.
Nie*_*eus 22
我也在调查这个话题,这是我的总结:
为什么这不起作用的根本原因OOTB(至少在使用validates_presence_of :article和不使用时validates_presence_of :article_id)是rails在内部不使用身份映射的事实,因此它本身不会知道article.comments[x].article == article
我找到了三个解决方法,使它能够轻松地工作:
class Article < ActiveRecord::Base
has_many :comments, :inverse_of => :article
end最后一个解决方案是本文中提到的bot,但似乎是rails的快速修复解决方案,因为缺少身份映射.它对我来说也是三个中最不具侵入性的一个.
小智 1
你是对的。文章需要一个 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
Run Code Online (Sandbox Code Playgroud)
如果您要在一种方法或操作中创建带有评论的新文章,那么我建议创建该文章并保存它,然后创建评论,但将整个内容包装在 Article.transaction 块中,这样您就不会结束补充任何额外的文章。
| 归档时间: |
|
| 查看次数: |
8943 次 |
| 最近记录: |