ข้อความแสดงข้อผิดพลาดในการตรวจสอบความถูกต้องสมบูรณ์แบบเองด้วย Rails


260

การใช้ Rails ฉันพยายามที่จะได้รับข้อความแสดงข้อผิดพลาดเช่น "ไม่สามารถเว้นว่างช่องเพลง" ในการบันทึก ทำดังต่อไปนี้:

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

... แสดงเฉพาะ "Song Rep XYW ต้องไม่ว่างเปล่า" ซึ่งไม่ดีเพราะชื่อของฟิลด์ไม่เป็นมิตรต่อผู้ใช้ ฉันจะเปลี่ยนชื่อฟิลด์เองได้อย่างไร? ฉันสามารถเปลี่ยนชื่อจริงของฟิลด์ในฐานข้อมูล แต่ฉันมีหลายช่อง "เพลง" และฉันจำเป็นต้องมีชื่อฟิลด์เฉพาะ

ฉันไม่ต้องการแฮ็กรอบกระบวนการตรวจสอบของรางและฉันรู้สึกว่าควรมีวิธีการแก้ไขที่

คำตอบ:


432

ตอนนี้วิธีที่ได้รับการยอมรับในการตั้งชื่อ humanized และข้อความผิดพลาดที่กำหนดเองคือการใช้สถานที่

# 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: guide.rubyonrails.org/i18n.html
Tyler Rick

4
โดยวิธีการ: หากคุณผ่านสัญลักษณ์สำหรับพารามิเตอร์ข้อความของตัวตรวจสอบความถูกต้องของคุณใน Rails 3.1.3 มันจะบอกคุณว่ามันกำลังมองหาขอบเขตที่มันจะไม่พบ e ดังนั้นคุณรู้ว่าสิ่งที่จะใส่ในของคุณ โลแคล yml
aceofspades

4
เอาล่ะนี่เป็นเรื่องดีและทุกอย่าง แต่ถ้าหากการเติมชื่อคอลัมน์อย่างไร้เดียงสา (ไม่ว่ามนุษย์จะอ่านได้) จะนำไปสู่ไวยากรณ์ f-uped ที่สมบูรณ์ (โดยเฉพาะอย่างยิ่งในภาษาที่ไม่ใช่ภาษาอังกฤษ) ฉันจำเป็นต้องใช้จริงerrors.add :base, msgหรือไม่? ฉันต้องการทราบว่ามีข้อผิดพลาดเกี่ยวกับคอลัมน์ใดดังนั้นฉันสามารถแสดงที่ช่องฟอร์มที่ถูกต้อง
panzi

6
@graywho บางทีฉันอาจจะพลาดอะไรบางอย่าง แต่มันไม่ได้เติมชื่อคอลัมน์ไว้ข้างหน้าข้อความหรือไม่ แม้ในภาษาอังกฤษฉันต้องการจะมีเช่น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

ไปแล้ว .. คุณสามารถเล่นกับ 2 สิ่งเหล่านี้และทำให้มันทำงาน
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
สำหรับ 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]

จนถึงตอนนี้เราแค่แสดงข้อความเดียวเท่านั้นสำหรับข้อผิดพลาดแรกเสมอ หากคุณต้องการแสดงข้อผิดพลาดทั้งหมดคุณสามารถวนซ้ำในแฮชและแสดงค่า

หวังว่าจะช่วย


16

รหัส Rails3 พร้อมข้อความที่แปลเป็นภาษาท้องถิ่นอย่างสมบูรณ์:

ใน model 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

เกี่ยวข้องกับคำตอบที่ยอมรับและคำตอบอื่น ๆ ในรายการ :

ฉันยืนยันว่าการแยก custom-err-msg ของ nanamkim นั้นใช้งานได้กับ 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 "custom_error_message" Gemfile ของคุณ - ดูgithubเพื่อดูรายละเอียดเพิ่มเติม
Dorian

สิ่งที่ฉันต้องการ
จริงๆ

3
@DickieBoy ฉันยืนยันว่าทางแยกของ nanamkim ( github.com/nanamkim/custom-err-msg ) ทำงานร่วมกับ Rails ได้จริง ๆ มันเล่นได้ดีกับคำตอบที่ยอมรับ ฉันจะเขียนคำตอบนี้แยกต่างหาก
Rystraum

@Rystraum สำหรับชีวิตของฉันฉันไม่สามารถจำ usecase รอบนี้ แต่ขอบคุณสำหรับการตอบกลับ! ฉันจะต้องจำไว้เพื่ออนาคต
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

ถ้าคุณต้องการที่จะแสดงรายการทั้งหมดในรายการที่ดี แต่ไม่ใช้ชื่อที่ไม่เป็นมิตรของ cruddy คุณสามารถทำเช่นนี้ ...

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 คุณสามารถแชร์รหัสของคุณได้ไหม
luckyruby

ฉันเดาว่าฉันต้องดูเพิ่มเติมคุณสามารถตรวจสอบรหัสและคำตอบของเขาที่นั่นstackoverflow.com/q/45128434/102133
Ben

0

ฉันลองติดตามแล้วทำงานให้ฉัน :)

1 งาน

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ติดต่อกลับที่จะแทนที่ข้อความการตรวจสอบว่าใน back-end ก่อนที่จะได้รับไปยังมุมมอง

  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 ชี้ให้เห็นการอ้างอิงอัญมณีนี้


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 %>

วิธี full_message ในที่อื่นคือสิ่งที่ Rails ใช้ภายในวิธี full_messages ดังนั้นมันจะให้ข้อผิดพลาด Rails ปกติสำหรับกรณีอื่น ๆ (Rails 3.2 ขึ้นไป)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.