2

アルバムとトラックの 2 つのモデルがあります。アルバムには多くのトラックがあり、トラックはアルバムに属します。

Railscasts のエピソード 197と同様に、アルバムの作成中に必要な数のトラックを作成できるようにしたいと考えています。ただし、Railscasts のエピソードとは異なり、Track フォームにはタイトルと説明の両方が含まれています (両方とも必須です)。

現在、フォームは次のようになっています。

Create New Album

Name: [      ]

    Track (remove link)
          Name:        [      ]
          Description: [      ]

    Track (remove link)
          Name:        [      ]
          Description: [      ]

(add track link)

フォームを空白で送信すると、フォームの上に次のエラー メッセージが表示されます。

Description can't be blank
Title can't be blank
Title can't be blank

これらのエラー メッセージはモデルに固有のものではなく、すべてページの上部にあり、モデルごとに 1 回だけ表示されます (両方のフィールドを空白のままにして、エラー メッセージが 1 回だけ表示されることに注意してください。どのトラックに固有のものでもありません)。 .


最初のトラック フィールドを生成するために、album_controller の新しいアクションに次の行を追加しました。2.times { @album.tracks.build }

私のフォームがどのように見えるかの要点は次のとおりです。

<% form_for @album do |f| %>
<%= f.error_messages %>

<%= f.label :title %><br />
<%= f.text_field :title %>

<% f.fields_for :tracks do |f, track| %>
  <%= render :partial => 'tracks/fields', :locals => {:f => f} %>
<% end %>

<%= f.submit "Submit" %>
<% end %>

<%= f.error_messages %>トップを<%= error_messages_for @album %>(アルバムのメッセージのみを表示する) に置き換え、<%= error_messages_for track %>(各トラックに固有のエラー メッセージを表示する) を追加しようとしましたが、うまくいきません。これにアプローチする方法を知っている人はいますか?

ありがとう!

4

4 に答える 4

3

親オブジェクトと子オブジェクトのエラー メッセージを分けたい場合は、少し複雑になる可能性があります。親オブジェクトを保存すると、子オブジェクトも検証され、子のエラーが含まれるためです。したがって、次のようなことができます。

<% form_for @album do |f| %>
<%= custom_error_messages_helper(@album) %>

<%= f.label :title %><br />
<%= f.text_field :title %>

<% f.fields_for :tracks do |t| %>
  <%= t.error_messages message => nil, :header_message => nil %>
  <%= render :partial => 'tracks/fields', :locals => {:f => t} %>
<% end %>

<%= f.submit "Submit" %>
<% end %>

t.error_messagesまたは、この行を部分的に配置することもできます(紛らわしいため、フォーム'tracks/fields'ビルダー オブジェクト form の名前を に変更しました)。特定の子オブジェクトのエラーのみを表示する必要があります(少なくとも私にとっては機能します)(したがって、どのオブジェクトのタイトルエラーかを確認できます)。また、Rails は、エラーを含むフィールドに css クラスを自動的に追加することにも注意してください。たとえば、css に追加します。ftfieldWithErrors

.fieldWithErrors {
  border: 1px solid red;
}

@album.errors親オブジェクトのエラーでは、子オブジェクトのエラーも含まれるため、より複雑になります。一部のエラーを削除したり、親オブジェクトに関連付けられているエラーのみを表示したりするための簡単で便利な方法が見つからなかったので、それを処理するカスタム ヘルパーを作成することを考えました。

def custom_error_messages_helper(album)
  html = ""
  html << '<div class="errors">'
  album.errors.each_error do |attr, error|
    if !(attr =~ /\./)
      html << '<div class="error">'
      html << error.full_message
      html << '</div>'
    end
  end
 html << '</div>'
end

「.」を含む名前の属性に関するすべてのエラーをスキップします。- そのため、親オブジェクトに関連付けられているすべてのエラーを出力する必要があります。唯一の問題は、ベースに追加されるエラーにあります-それらのattr値はbase、親オブジェクトのエラーに追加される子オブジェクトにベースにエラーが追加される方法がわからないためです。おそらくそれらのattr値もbase同じであるため、このヘルパーに出力されます。でも、使わなくても問題ありませんadd_to_base

于 2010-03-03T14:16:53.670 に答える
1

まず、 f と f はスコープを混同します。fields_for セクションに「g」などを使用すると、スコープが理解されます。

次に試してください:

<% form_for @album do |f| %>
  <%= f.error_messages %>

  <%= f.label :title %><br />
  <%= f.text_field :title %>

  <% f.fields_for :tracks do |g, track| %>
    <%= g.error_messages -%>
    <%= render :partial => 'tracks/fields', :locals => {:f => g} %>
  <% end %>

  <%= f.submit 'Create' %>
<% end %>

これをaccepts_nested_attributes_for :tracksアルバム モデルで使用します。

私はこれを自分でテストしましたが、動作します。個々のトラックのエラーは、トラックのセクション内に表示されます。

Railsの最新バージョンを使用しています。

于 2010-02-27T22:32:15.760 に答える
0

これを試しましたか?

<% f.fields_for :tracks do |f, track| %>
  <%= error_messages_for "track" %>
  <%= render :partial => 'tracks/fields', :locals => {:f => f} %>
<% end %>
于 2010-02-27T04:44:47.270 に答える
0

上記と同様ですが、以下のコードを使用すると、任意のオブジェクトまたはオブジェクトの配列のエラーをテストできます。

<%= show_errors( [@company, @estabs], :header_ref => 'Company' ) %>

def show_errors(objarray, opt)

    return '' if objarray.blank?

    err = [ ]
    html  = ""

    objarray.each { |obj|  
            if obj.is_a?(Array)
                obj.each { |oo| html << show_errors([oo], opt) }
            elsif (obj.errors.count > 0 ) 
                err << obj.errors.full_messages #didnt worked with gem i18n 0.5.0
            end
              }

    return '' if (err.count==0) and (html.blank?)

    if err.count > 0
        err.flatten!            #remove sub-arrays
        err.each { |x| x.strip! }   #strip:remove espaces
        err.uniq!               #remove duplicated messages
        err.sort!

        header_ref = opt[:header_ref].nil?  ?  ""  :  opt[:header_ref]

        erro_str = (err.count == 1) ? 'erro' : 'erros'
        erro_verb = (err.count == 1) ? 'ocorreu' : 'ocorreram'

        html << '<div class="erros"  id="erros"> '
        html <<  "<b> #{header_ref}: #{err.count.to_s}  #{erro_str} #{erro_verb}: </b> "
        html << '<ul> ' 

        err.each  { |e| html << '<li> ' + e + ' </li>' }

        html << '</ul> </div>'
    end
    return html
end
于 2011-01-18T18:41:11.063 に答える