Railsでの完全にカスタムの検証エラーメッセージ


260

Railsを使用して、保存時に「曲フィールドを空にすることはできません」などのエラーメッセージを表示しようとしています。以下を実行します。

validates_presence_of :song_rep_xyz, :message => "can't be empty"

...「Song Rep XYWは空にできません」と表示されるだけですが、フィールドのタイトルがわかりにくいため、これは適切ではありません。フィールド自体のタイトルを変更するにはどうすればよいですか?データベース内のフィールドの実際の名前を変更することはできますが、「歌」フィールドが複数あり、特定のフィールド名を指定する必要があります。

Railsの検証プロセスをハッキングしたくないので、それを修正する方法があるはずだと思います。

回答:


432

現在、人にわかりやすい名前とカスタムエラーメッセージを設定するには、ロケール使用する方法が受け入れられています

# config/locales/en.yml
en:
  activerecord:
    attributes:
      user:
        email: "E-mail address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "is required"

これで、「email」属性の人間化された名前プレゼンス検証メッセージが変更されました。

検証メッセージは、特定のモデル+属性、モデル、属性、またはグローバルに設定できます。


19
mongoidを使用している場合は、activerecord:をmongoid:に置き換えます
Intentss

88
@graywh:コメントにない場合、回答に関する質問はどこに投稿する必要がありますか?I18n
タイラーリック

4
ちなみに、Rails 3.1.3のバリデーターのメッセージパラメータにシンボルを渡すと、見つからなかったため、探していたスコープがわかります。ロケールyml。
aceofspades

4
まあ、これで問題ありませんが、単純に列名を前に付けると(人間が読める程度に関係なく)、文法が完全にf-upになります(特に英語以外の言語)。本当に使用する必要がありますerrors.add :base, msgか?エラーがどの列に関するものか知りたいので、正しいフォームフィールドに表示できます。
パンジー2013

6
@graywh何かが足りないかもしれませんが、メッセージの前に常に列名が付加されるわけではありませんか?でも英語Iに例えばを持っているしたいと思いますThe password is wrong.The email address is not valid.の代わりに、Password is wrong.Email is not valid.
panzi

65

あなたのモデルでは:

validates_presence_of :address1, message: 'Put some address please' 

あなたの見解では

<% m.errors.each do |attr, msg|  %>
 <%= msg %>
<% end %>

代わりに行う場合

<%= attr %> <%= msg %>

あなたは属性名でこのエラーメッセージを受け取ります

address1 Put some address please

1つの属性のエラーメッセージを取得する場合

<%= @model.errors[:address1] %>

それは許容できる解決策ではありません。他のすべての属性(attr + msg)のデフォルトの動作が必要な場合はどうなりますか?
ロムロCeccon

そこに行きます..あなたはそれら2つのことで遊んでそれを機能させることができます
フェデリコ

それはあなたYMLファイルで検索しますので、あなたは次のように、記号を使用する必要がありますvalidates_presence_of :address1, :message => :put_some_address_please
フェデリコ

フィールド名が含まれるため、これは受け入れられません
fatuhoku

62

これを試して。

class User < ActiveRecord::Base
  validate do |user|
    user.errors.add_to_base("Country can't be blank") if user.country_iso.blank?
  end
end

ここで見つけ

これを行う別の方法を次に示します。実行することは、モデルクラスでhuman_attribute_nameメソッドを定義することです。メソッドには列名が文字列として渡され、検証メッセージで使用する文字列が返されます。

class User < ActiveRecord::Base

  HUMANIZED_ATTRIBUTES = {
    :email => "E-mail address"
  }

  def self.human_attribute_name(attr)
    HUMANIZED_ATTRIBUTES[attr.to_sym] || super
  end

end

上記のコードはここからです


問題は、私のフィールドが:song_rep_xyz(まあ、複雑なもの)と呼ばれることです。これはユーザーフレンドリーではありません
marcgg

16
Rails 3の場合、「def self.human_attribute_name(attr)」を「def self.human_attribute_name(attr、options = {})」に変更する必要があります。それ以外の場合はエラーを返します
spacemonkey

3
これをありがとう。Rails 2で機能するものが必要でした。(はい、私にかわいそうです... :)
Dan Barron

18

はい、プラグインなしでこれを行う方法があります!ただし、前述のプラグインを使用する場合ほどクリーンでエレガントではありません。ここにあります。

Rails 3(以前のバージョンと異なるかどうかはわかりません)だとすると、

これをモデルに保持します。

validates_presence_of :song_rep_xyz, :message => "can't be empty"

ビューでは、去るのではなく

@instance.errors.full_messages

足場ジェネレータを使用する場合と同様に、次のように記述します。

@instance.errors.first[1]

そして、属性名なしで、モデルで指定したメッセージのみを取得します。

説明:

#returns an hash of messages, one element foreach field error, in this particular case would be just one element in the hash:
@instance.errors  # => {:song_rep_xyz=>"can't be empty"}

#this returns the first element of the hash as an array like [:key,"value"]
@instance.errors.first # => [:song_rep_xyz, "can't be empty"]

#by doing the following, you are telling ruby to take just the second element of that array, which is the message.
@instance.errors.first[1]

これまでのところ、常に最初のエラーに対して、メッセージを1つだけ表示しています。すべてのエラーを表示したい場合は、ハッシュでループして値を表示できます。

お役に立てば幸いです。


16

完全にローカライズされたメッセージを含むRails3コード:

モデルuser.rbで検証を定義します

validates :email, :presence => true

config / locales / en.yml

en:  
  activerecord:
    models: 
      user: "Customer"
    attributes:
      user:
        email: "Email address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "cannot be empty"

15

カスタム検証メソッドで次を使用します。

errors.add(:base, "Custom error message")

add_to_baseは非推奨になっているため。

errors.add_to_base("Custom error message")


13

受け入れられた回答リストの下の別の回答に関連する:

nanamkimのcustom-err-msgのフォークが Rails 5とロケール設定で動作することを確認しています。

ロケールメッセージをキャレットで開始するだけで、メッセージに属性名が表示されません。

次のように定義されたモデル:

class Item < ApplicationRecord
  validates :name, presence: true
end

次のようにen.yml

en:
  activerecord:
    errors:
      models:
        item:
          attributes:
            name:
              blank: "^You can't create an item without a name."

item.errors.full_messages 表示されます:

You can't create an item without a name

通常の代わりに Name You can't create an item without a name


11

custom_error_message gem(またはプラグインとして)をインストールすることをお勧めしますDavid Easleyによって最初に作成され)を

次のようなことができます:

validates_presence_of :non_friendly_field_name, :message => "^Friendly field name is blank"

私は過去にこのプラグインを使用したことがありますが、定期的にメンテナンスされているようには見えませんが、大きな成功を収めています。
Jared Brown

1
Rails 3のgemとしてインストールすることもできgem "custom_error_message" ます。Gemfileに追加するだけです。詳細はgithubを参照してください
Dorian

まさに私が必要としていたもの
olleicua

3
@DickieBoy私はnanamkimのフォーク(github.com/nanamkim/custom-err-msg)がRails 5で動作することを確認します。これについては別の回答として書きます。
Rystraum 2016年

@Rystraum私の人生では、これに関するユースケースを思い出せませんが、返信ありがとうございます。必ず覚えておきます。
DickieBoy 2016年

10

1つの解決策は、i18nのデフォルトのエラー形式を変更することです。

en:
  errors:
    format: "%{message}"

デフォルトは format: %{attribute} %{message}


7

ここに別の方法があります:

このテンプレートを使用する場合:

<% if @thing.errors.any? %>
  <ul>
    <% @thing.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
  </ul>
<% end %>

次のような独自のカスタムメッセージを作成できます。

class Thing < ActiveRecord::Base

  validate :custom_validation_method_with_message

  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:_, "My custom message")
    end
  end

このように、アンダースコアのため、メッセージ全体が「私のカスタムメッセージ」になりますが、最初の余分なスペースは目立ちません。最初に余分なスペースが必要ない場合は、.lstripメソッドを追加してください。

<% if @thing.errors.any? %>
  <ul>
    <% @thing.errors.full_messages.each do |message| %>
      <li><%= message.lstrip %></li>
    <% end %>
  </ul>
<% end %>

String.lstripメソッドは、 ':_'によって作成された余分なスペースを取り除き、その他のエラーメッセージは変更しません。

またはさらに良いことに、カスタムメッセージの最初の単語をキーとして使用します。

  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:my, "custom message")
    end
  end

これで、メッセージ全体が「My custom message」になり、余分なスペースはありません。

メッセージ全体を「URLを空白にすることはできません」のように大文字で始まる単語で開始する場合は、実行できません。代わりに、他の単語をキーとして追加してみてください。

  def custom_validation_method_with_message
    if some_model_attribute.blank?
      errors.add(:the, "URL can't be blank")
    end
  end

メッセージ全体は「URLを空白にすることはできません」になります


ああ、あなたerrors.add(:_, 'foobar')はメッセージとして「foobar」を実行して取得することさえできます
xxjjnn

6

通常の方法で実行してください:

validates_presence_of :email, :message => "Email is required."

代わりにこのように表示します

<% if @user.errors.any? %>
  <% @user.errors.messages.each do |message| %>
    <div class="message"><%= message.last.last.html_safe %></div>
  <% end %>
<% end %>

戻り値

"Email is required."

ローカリゼーションの方法は間違いなくこれを行う「適切な」方法ですが、グローバルではないプロジェクトを少しだけ行って、すぐに始めたい場合は、ファイルをホッピングするよりも簡単です。

文字列の先頭以外の場所にフィールド名を置くことができる点が気に入っています。

validates_uniqueness_of :email, :message => "There is already an account with that email."

2

それらすべてを素敵なリストにリストしたいが、人間味のない無愛想な名前を使用せずに、これを行うことができます...

object.errors.each do |attr,message|
  puts "<li>"+message+"</li>"
end

1

あなたの見解では

object.errors.each do |attr,msg|
  if msg.is_a? String
    if attr == :base
      content_tag :li, msg
    elsif msg[0] == "^"
      content_tag :li, msg[1..-1]
    else
      content_tag :li, "#{object.class.human_attribute_name(attr)} #{msg}"
    end
  end
end

属性名なしでエラーメッセージをオーバーライドする場合は、次のようにメッセージの先頭に^を追加します。

validates :last_name,
  uniqueness: {
    scope: [:first_name, :course_id, :user_id],
    case_sensitive: false,
    message: "^This student has already been registered."
  }

Rails 5.1 / Ruby 2.4では動作しませんか?そのスコープでモデル名を取得
Ben

@Benは、Rails 5.1.2、Ruby 2.4.1p111で動作します。コードを共有できますか?
ラッキールビー

私はさらに調査しなければならなかったと思います、あなたはコードと彼の答えをそこでチェックすることができますstackoverflow.com/q/45128434/102133
Ben

0

私は以下を試してみました、私のために働いた:)

1 job.rb

class Job < ApplicationRecord
    validates :description, presence: true
    validates :title, 
              :presence => true, 
              :length => { :minimum => 5, :message => "Must be at least 5 characters"}
end

2 jobs_controller.rb

def create
      @job = Job.create(job_params)
      if @job.valid?
        redirect_to jobs_path
      else
        render new_job_path
      end     
    end

3 _form.html.erb

<%= form_for @job do |f| %>
  <% if @job.errors.any? %>
    <h2>Errors</h2>
    <ul>
      <% @job.errors.full_messages.each do |message|%>
        <li><%= message %></li>
      <% end %>  
    </ul>
  <% end %>
  <div>
    <%= f.label :title %>
    <%= f.text_field :title %>
  </div>
  <div>
    <%= f.label :description %>
    <%= f.text_area :description, size: '60x6' %>

  </div>
  <div>
    <%= f.submit %>
  </div>
<% end %> 

0

まだ必要な場合に役立つコードを以下に示します。私のモデル:

validates :director, acceptance: {message: "^Please confirm that you are a director of the company."}, on: :create, if: :is_director?

次に、メッセージを表示するヘルパーを作成しました。

module ErrorHelper
  def error_messages!
    return "" unless error_messages?
    messages = resource.errors.full_messages.map { |msg|
       if msg.present? && !msg.index("^").nil?
         content_tag(:p, msg.slice((msg.index("^")+1)..-1))
       else
         content_tag(:p, msg)
       end
    }.join

    html = <<-HTML
      <div class="general-error alert show">
        #{messages}
      </div>
    HTML

    html.html_safe
  end

  def error_messages?
    !resource.errors.empty?
  end
end

0

誰も言及したことのないユニークなアプローチ!

必要なすべてのカスタマイズを取得できる唯一の方法は、after_validationコールバックを使用してエラーメッセージを操作できるようにすることでした。

  1. 検証メッセージが通常どおり作成されるようにします。検証ヘルパーでメッセージを変更する必要はありません。

  2. after_validationビューに到達する前に、バックエンドでその検証メッセージを置き換えるコールバックを作成します。

  3. このafter_validationメソッドでは、通常の文字列と同じように、検証メッセージを使用して好きなことができます。動的な値を使用して、検証メッセージに挿入することもできます。


#this could be any validation
validates_presence_of :song_rep_xyz, :message => "whatever you want - who cares - we will replace you later"

after_validation :replace_validation_message

def replace_validation_message
    custom_value = #any value you would like
    errors.messages[:name_of_the_attribute] = ["^This is the replacement message where 
    you can now add your own dynamic values!!! #{custom_value}"]
end

after_validationメソッドのスコープは組み込みのレール検証ヘルパーよりもはるかに大きいため、object.file_nameを使用する場合と同じように、検証するオブジェクトにアクセスできます。これは、それを呼び出そうとしている検証ヘルパーでは機能しません。

注:^@Rystraumがこのgemの参照を指摘しているため、検証の開始時に属性名を取り除くためにを使用します


0

フィールド名の表示で実際にロケールが異なる場合は、graywhの答えが最適です。(表示する他のフィールドに基づく)動的フィールド名の場合、私はこのようなことをします

<% object.errors.each do |attr, msg| %>
<li>
  <% case attr.to_sym %>
  <% when :song_rep_xyz %>
    <%= #display error how you want here %>
  <% else %>
    <%= object.errors.full_message(attr, msg) %>
  <% end %>
</li>
<% end %>

elseのfull_messageメソッドは、railsがfull_messagesメソッドの内部で使用するものであるため、他の場合(Rails 3.2以上)の通常のRailsエラーを出力します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.