我的问题是:为什么.becomes
没有将错误传递给新对象?这不是预期的行为吗?
我在rails app中有以下单表继承类:
class Document < ActiveRecord::Base
validates :title, :presence => true
end
class LegalDocument < Document
end
class MarketingDocument < Document
end
我想使用相同的控制器和一组视图来编辑LegalDocument
和MarketingDocument
,因此我使用DocumentsController < ApplicationController
以及edit
和{ {1}}行动:
update
以及def edit
@document = Document.find(params[:id])
end
def update
@document = Document.find(params[:id])
if @document.update_attributes(params[:document])
redirect_to documents_path, :notice => "#{t(:Document)} was successfully updated."
else
render :action => "edit"
end
end
视图中的以下内容:
edit
从调试开始,我知道它没有显示,因为<%= form_for @document.becomes(Document) do |f| %>
<% if f.object.errors.present? %>
<div class="error_message">
<h4><%= pluralize(f.object.errors.count, 'error') %> occurred</h4>
</div>
<% end %>
<div>
<%= f.label :title %>
<%= f.text_field :title, :class => "inputText" %>
</div>
<%= f.submit %>
<% end %>
是零。 但是,从调试开始,我也知道f.object.errors
并非正如预期的那样。
我的问题是:为什么@document.errors
没有将错误传递给新对象?这不是预期的行为吗?
答案 0 :(得分:2)
是的,我也注意到了。
只需按f.object.errors.present?
(或@document.errors.any?
)更改@document.errors.present?
。
如果您真的想使用f.object.errors.present?
,请在控制器中编写becomes
(编辑和更新操作),而不是在视图中:
def edit
@document = Document.find(params[:id]).becomes(Document)
end
def update
@document = Document.find(params[:id]).becomes(Document)
# ....
end
然后在视图中:
<%= form_for @document do |f| %>
<% if f.object.errors.present? %>
<p>Errrorsss....</p>
<% end %>
#.....
这是因为表单的url是根据@ document.becomes(Document)(=&gt; PUT document/:id
)构建的,但@document是根据其“true”类(Document的子类)创建的
如果你有撬(强烈推荐),请写:
def update
@document = Document.find(params[:id])
binding.pry
# ...
end
然后检查@document。即使您在表单中调用了@document.becomes(Document)
,您也会看到@document是LegalDocument的实例或其他子类。
因此,最终f.object
和@document
不一样。
这解释了为什么在验证失败时看不到f.object.errors
的原因。
修改强>
处理STI和表单的“最佳方式”是不使用becomes
:
<= form_for @document, url: { controller: 'documents', action: 'update' }, as: :document do |f| %>
<% if @document.errors.any? %>
# or if f.object.errors.any?
# handle validation errors
<% end %>
# your form...
<% end %>
这使您:
只有一个控制器(documents_controller)
只有一个资源(资源:文档)
它会跟踪您的子类:LegalDocument将存储为LegalDocument。 无转化:您无需在转换为Document之前存储其类,然后再重新分配。
另外,您的子类在您的表单中可用,因此您可以(让我们想象)为该类型构建select
。
您的控制器看起来更干净:@document = Document.find params[:id]
仅此而已。就像一个经典的资源。
如果您想在不同的操作(通常为edit
和new
)之间共享此表单,请执行以下操作:
<%= form_for @document, url: { controller: 'media_files', action: action }, as: :media_file do |f| %>%>
# edit.html.erb
<%= render 'form', action: 'update' %>
# new.html.erb
<%= render 'form', action: 'create' %>
答案 1 :(得分:1)
几乎它是一个错误,它应该按照你最初的预期工作。解决这个问题的以下补丁看起来像是在10月份撤回了
https://github.com/lazyatom/rails/commit/73cb0f98289923c8fa0287bf1cc8857664078d43