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"

이제 "이메일"속성에 대한 인간화 된 이름 현재 상태 확인 메시지가 변경되었습니다.

유효성 검사 메시지는 특정 모델 + 속성, 모델, 속성 또는 전체적으로 설정할 수 있습니다.


19
mongoid를 사용하는 경우 activerecord :를 mongoid :로 바꾸십시오.
Intentss

88
@ graywh : 의견에없는 경우 답변에 대한 질문을 어디에 게시해야합니까? 다음은 I18n 안내서입니다 : guides.rubyonrails.org/i18n.html
Tyler Rick

4
그건 그렇고 : Rails 3.1.3에서 유효성 검사기의 메시지 매개 변수에 기호를 전달하면 찾을 수없는 범위를 알려 주므로 정확히 무엇을 입력 해야하는지 알 수 있습니다. 로케일 yml.
aceofspades

4
글쎄, 이것은 훌륭하지만 모두 열 이름 앞에 (사람이 읽을 수있는 방식에 관계없이) 접두어 문법 (특히 영어가 아닌 언어로)을 만들면 어떻게 될까요? 정말로 사용해야 errors.add :base, msg합니까? 오류가 발생한 열을 알고 싶습니다. 올바른 양식 필드에 표시 할 수 있습니다.
panzi

6
@ graywh 어쩌면 뭔가 빠졌지 만 항상 메시지 앞에 열 이름을 추가하지는 않습니까? 심지어 영어로 나는 예를 들어 가지고 싶습니다 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

하나의 단일 속성에 대한 오류 메시지를 받으려면

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

수용 가능한 해결책이 아닙니다. 다른 모든 속성 (attr + msg)에 대한 기본 동작을 원하는 경우 어떻게합니까?
Rômulo Ceccon

거기 당신은 .. 당신은 그 두 가지와 함께 연주하고 작동하게 할 수 있습니다
Federico

yml 파일에서 기호가 표시되도록 기호를 사용해야합니다.validates_presence_of :address1, :message => :put_some_address_please
Federico

필드 이름이 포함되어 있으므로 허용되지 않습니다
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
레일 3 "데프 self.human_attribute_name (ATTR)"요구 그렇지 않으면 오류가 반환, "데프 self.human_attribute_name (ATTR, 옵션 = {})"로 변경하기
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]

지금까지 첫 번째 오류에 대해 하나의 메시지 만 표시했습니다. 모든 오류를 표시하려면 해시를 반복하고 값을 표시하십시오.

도움이 되었기를 바랍니다.


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
레일 3의 젬으로 설치할 수도 gem "custom_error_message" 있습니다. Gemfile에 추가 하기 만하면 됩니다. 자세한 내용 은 github 참조
Dorian

정확히 내가 필요한 것
olleicua

3
@DickieBoy nanamkim의 포크 ( github.com/nanamkim/custom-err-msg )가 Rails 5에서 작동 한다는 것을 확인했습니다 . 실제로 받아 들인 대답으로 훌륭하게 재생됩니다. 이것을 별도의 답변으로 작성하겠습니다.
Rystraum

@Rystraum 내 인생에서 나는 이것 주위의 유스 케이스를 기억할 수 없지만 답장을 보내 주셔서 감사합니다! 나는 미래를 위해 그것을 기억할 것입니다.
DickieBoy

10

한 가지 해결책은 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

이제 전체 메시지는 추가 공간없이 "내 사용자 정의 메시지"가됩니다.

"URL은 비워 둘 수 없습니다"와 같이 대문자로 된 단어로 전체 메시지를 시작하려면 수행 할 수 없습니다. 대신 다른 단어를 키로 추가하십시오.

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

이제 전체 메시지는 "URL은 비워 둘 수 없습니다"입니다.


ooo, 당신은 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."
  }

레일 5.1 / 루비 2.4에서는 작동하지 않습니까? 해당 범위에서 모델 이름 얻기
Ben

@Ben은 Rails 5.1.2, Ruby 2.4.1p111에서 작동합니다. 코드를 공유 할 수 있습니까?
luckyruby

나는 더 자세히보아야한다고 생각한다. 코드와 그의 대답을 확인할 수있다 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

jobs_controller.rb 2 개

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 메소드는 내장 된 Rails 유효성 검증 헬퍼보다 훨씬 더 넓은 범위를 가지므로, 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 이상).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.