web-dev-qa-db-ja.com

f.error_messages in Rails 3.0

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変数を使用することを理解していますが、前者ではコメント作成のエラーメッセージを取得するためにどの変数を参照しますか?

42
Craig Smitham

Docrailsのgithubの問題を調べたところ、コメントの検証方法を説明する代わりにf.error_messagesを削除することにしました。

0
bunwich

フォームに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

そしてそれだけです。

23
Nicolas Blanco

あなたがする必要があるのは参照@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)

表示ロジックでそれらをループして、各コメントエラーを出力します。

13
Lukas

この機能はスタンドアロン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_をフォームビルダーに追加します。

7
Justin Tanner

これがエラーシーン全体に対する私の解決策です。

レンダリング時に渡すモデル変数を単純に使用するパーシャルを作成しました。

<%# 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
3
Benjamin

[@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メソッドを質問に追加してください。

1
Matt