2011-10-24 15 views
32

私はこれをどのように達成できるかを理解しようとしています。誰かが私に助言をしたり、正しい方向に私を指摘することはできますか?一度に1つずつRuby on Railsフォーム検証エラーメッセージを表示する方法

これにより、一度に各フィールドから1エラーを表示できます。それは私がやりたいことですが、それほど正確ではありません。私は一度に1つの完全なエラーメッセージを表示したい。例えば。ファーストネームは空白にできません。それが解決されると、次のエラーに移ります。ユーザーが最後の名前に数字を追加した場合、それ以上は空白にならず、文字のみが許可されていることを示す別のエラーが表示されます。エラーが修正されたときには、彼らの姓を正しく出す。

<% @user.errors.each do |attr, msg| %> 
<%= "#{attr} #{msg}" if @user.errors[attr].first == msg %> 
<% end %> 

答えて

26

数時間の実験の後、私はそれを理解しました。

<% if @user.errors.full_messages.any? %> 
    <% @user.errors.full_messages.each do |error_message| %> 
    <%= error_message if @user.errors.full_messages.first == error_message %> <br /> 
    <% end %> 
<% end %> 

さらに良い:

​​
+1

さらに優れています。f.object.errors.anyなら '<%= f.object.errors.full_messages.join("、 ")? %> ' - これはオブジェクトとエラーの長さに依存しません。 'f'はフォーム変数です。 –

48

ActiveRecordは、errorsという配列に検証エラーを格納します。あなたがUserモデルを持っているなら、あなたはそのように指定されたインスタンスで検証エラーにアクセスします。もちろん

@user = User.create[params[:user]] # create will automatically call validators 

if @user.errors.any? # If there are errors, do something 

    # You can iterate through all messages by attribute type and validation message 
    # This will be something like: 
    # attribute = 'name' 
    # message = 'cannot be left blank' 
    @user.errors.each do |attribute, message| 
    # do stuff for each error 
    end 

    # Or if you prefer, you can get the full message in single string, like so: 
    # message = 'Name cannot be left blank' 
    @users.errors.full_messages.each do |message| 
    # do stuff for each error 
    end 

    # To get all errors associated with a single attribute, do the following: 
    if @user.errors.include?(:name) 
    name_errors = @user.errors.on(:name) 

    if name_errors.kind_of?(Array) 
     name_errors.each do |error| 
     # do stuff for each error on the name attribute 
     end 
    else 
     error = name_errors 
     # do stuff for the one error on the name attribute. 
    end 
    end 
end 

あなたはまた、代わりに、コントローラのビューでは、このいずれかを行うことができ、あなただけ表示する必要がありますユーザーまたは何かに最初のエラー。

+2

私はRails 4.2.0を使用しています。あなたのコードは私のためには機能しませんでした。代わりに '@ user.errors.invalid?(:name)'から '@ user.errors.include?(:name)'に変更しなければなりませんでした。 – anka

+0

これは今までスタックオーバーフローで見た最も詳細な答えです。優れた。 –

+0

使用したメソッド '.on()'でドキュメントを見つけることができません。 Rubyクラスの "Hash" docには表示されませんか? – Douglas

5

良いアイデア、

あなただけのテキストフィールドの下にエラーメッセージを入れたい場合は、この

.row.spacer20top 
    .col-sm-6.form-group 
    = f.label :first_name, "*Your First Name:" 
    = f.text_field :first_name, :required => true, class: "form-control" 
    = f.error_message_for(:first_name) 
のように行うことができます

0とは?
- >まあ、これはSCSS対応するエラー

<div id="error_user_email" for="user_email" class="signup-error alert alert-danger">has already been taken</div> 
<script>document.onreadystatechange = function(){$('#error_user_email').parent().addClass('has-signup-error');}</script> 

後に生成されたいくつかのクールなもの

# Author Shiva Bhusal 
# Aug 2016 
# in config/initializers/modify_rails_form_builder.rb 
# This will add a new method in the `f` object available in Rails forms 
class ActionView::Helpers::FormBuilder 
    def error_message_for(field_name) 
    if self.object.errors[field_name].present? 
     model_name    = self.object.class.name.downcase 
     id_of_element   = "error_#{model_name}_#{field_name}" 
     target_elem_id   = "#{model_name}_#{field_name}" 
     class_name    = 'signup-error alert alert-danger' 
     error_declaration_class = 'has-signup-error' 

     "<div id=\"#{id_of_element}\" for=\"#{target_elem_id}\" class=\"#{class_name}\">"\ 
     "#{self.object.errors[field_name].join(', ')}"\ 
     "</div>"\ 
     "<!-- Later JavaScript to add class to the parent element -->"\ 
     "<script>"\ 
      "document.onreadystatechange = function(){"\ 
      "$('##{id_of_element}').parent()"\ 
      ".addClass('#{error_declaration_class}');"\ 
      "}"\ 
     "</script>".html_safe 
    end 
    rescue 
    nil 
    end 
end 

結果 enter image description here

マークアップを行うには美しいハックです

.has-signup-error{ 
    .signup-error{ 
     background: transparent; 
     color: $brand-danger; 
     border: none; 
    } 

    input, select{ 
     background-color: $bg-danger; 
     border-color: $brand-danger; 
     color: $gray-base; 
     font-weight: 500; 
    } 

    &.checkbox{ 
     label{ 
     &:before{ 
      background-color: $bg-danger; 
      border-color: $brand-danger; 
     } 
     } 
    } 

注:エラーメッセージのロケールを使用している

<% @user.errors.each do |attr, msg| %> 
    <li> 
    <%= @user.errors.full_messages_for(attr).first if @user.errors[attr].first == msg %> 
    </li> 
<% end %> 

この方法:ここ

1

使用される変数ブートストラップ私はこのようにそれを解決しました。

関連する問題