Rails 3.0ではf.error_messages
が非推奨になり、正しく動作するためにプラグインが必要になりました-ただし、(新しい)ネイティブな方法でエラーメッセージを表示する方法を学びたいです。 スタートガイド に従っています。これは、コメントフォームを実装するときに非推奨のメソッドを使用します。例えば:
<h2>Add a comment:</h2>
<%= form_for([@post, @post.comments.build]) do |f| %>
<%= f.error_messages %>
<div class="field">
<% f.label :commenter %><br />
<%= f.text_field :commenter %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
これを行う正しい方法は次のとおりです(scaffoldによって生成されます)。
<%= form_for(@post) do |f| %>
<% if @post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% @post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
. . .
後者の例では@post
変数を使用することを理解していますが、前者ではコメント作成のエラーメッセージを取得するためにどの変数を参照しますか?
Docrailsのgithubの問題を調べたところ、コメントの検証方法を説明する代わりにf.error_messagesを削除することにしました。
フォームにerror_messagesを実装するための最良かつクリーンな方法は、FormBuilderにerror_messagesを実装することです。
たとえば、最後のプロジェクトに実装したerror_messagesメソッドは次のとおりです。独自のFormBuilderを実装することにより、Webデザイナーのルールとスタイルに従うことができます...以下は、ul/liのエラーリストをいくつかのカスタムスタイルで出力する例です。
class StandardBuilder < ActionView::Helpers::FormBuilder
def error_messages
return unless object.respond_to?(:errors) && object.errors.any?
errors_list = ""
errors_list << @template.content_tag(:span, "There are errors!", :class => "title-error")
errors_list << object.errors.full_messages.map { |message| @template.content_tag(:li, message) }.join("\n")
@template.content_tag(:ul, errors_list.html_safe, :class => "error-recap round-border")
end
end
次に、私のフォームで:
= f.error_messages
そしてそれだけです。
あなたがする必要があるのは参照@post.comments
そのため、次のようなことができます。
<% @post.comments.each do |comment| %>
<% if comment.errors.any? %>
<% comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>
<% end %>
または、すべてのエラーを引き出します:
comment_errors = @post.comments.map(&:errors)
表示ロジックでそれらをループして、各コメントエラーを出力します。
この機能はスタンドアロンgem dynamic_form として存在します。
以下をGemfile
に追加します
_gem 'dynamic_form'
_
githubページ から:
DynamicFormには、Rails3モデルの処理に役立ついくつかのヘルパーメソッドがあります。
input(record, method, options = {})
form(record, options = {})
error_message_on(object, method, options={})
error_messages_for(record, options={})
また、_f.error_messages
_および_f.error_message_on
_をフォームビルダーに追加します。
これがエラーシーン全体に対する私の解決策です。
レンダリング時に渡すモデル変数を単純に使用するパーシャルを作成しました。
<%# app/views/errors/_error.html.erb %>
<%= content_for :message do %>
<% if model.errors.any? %>
<ul>
<% model.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<% end %>
モデルの名前と一般的な名前に基づいて、動的なHTMLクラスやID名を簡単に追加できます。
エラーメッセージがレイアウトファイル内のすべての同じ場所に表示されるように設定します。
<%# app/views/layouts/application.html.erb %>
<%= yield :message %>
その機能が必要ない場合は、パーシャルのcontent_forを削除するとうまくいきます。
その後、実際に任意のビューで次のように書くことができます。
<%= render 'errors/error', model: @some_model %>
コレクションを取得し、上記の部分エラーを活用する部分を作成することで、これをさらに拡張できます。
<%# app/views/errors/_collection.html.erb %>
<% collection.each do |model| %>
<%= render 'errors/error', model: model %>
<% end %>
でレンダリング:
<%= render 'errors/collection', collection: @some_model.some_has_many_association %>
私はこの方法が好きです。シンプルで、管理/保守が簡単で、信じられないほど微調整が可能です。
これがお役に立てば幸いです!
編集:HAMLのすべて
-# app/views/errors/_error.html.haml
= content_for :message do
- if model.errors.any?
%ul
- model.errors.full_messages.each do |msg|
%li= msg
-# app/views/layouts/application.html.haml
= yield :message
= render 'errors/error', model: @some_model
-# app/views/errors/_collection.html.haml
- collection.each do |model|
= render 'errors/errors', model: @some_model
= render 'errors/_collection', collection: @some_model.some_has_many_association
[@post, @post.comments.build]
配列はpolymorphic_path
内のform_for
に渡されただけだと思います。これにより、コメントのサブリソースパス(この場合は/posts/1/comments
など)が生成されます。最初の例では、コメントを投稿のサブリソースとして使用しているようです。
したがって、実際にここで呼び出されるコントローラーはCommentsController
です。 Lukasのソリューションが機能しない理由は、コメントを作成するときにコントローラー内で@ post.comments.buildを実際に使用しないためかもしれません(form_for
を呼び出すときにビューで使用することは問題ではありません) )。 CommentsController#create
メソッドは次のようになります(多かれ少なかれ):
def create
@post = Post.find(params[:post_id]
@comment = @post.comments.build(params[:comment])
if(@comment.save)
# you would probably redirect to @post
else
# you would probably render post#show or wherever you have the form
end
end
その後、scaffoldingによって生成されたコードを使用できます。@post
呼び出しを除くすべての行で、@comment
インスタンス変数をform_for
に置き換えるだけです。
このフォームを表示するコントローラーメソッドに@comment = @post.comment.build
を追加し、エラーが発生した場合にform_for([@post, @comment], ...)
を使用してフォームの内容をフォームに表示したままにすることも良い考えだと思います。
これが機能せず、理解できない場合は、CommentsController#create
メソッドを質問に追加してください。