[英]Fully custom validation error message with Rails
使用 Rails 我試圖在保存時收到一條錯誤消息,如“歌曲字段不能為空”。 執行以下操作:
validates_presence_of :song_rep_xyz, :message => "can't be empty"
... 只顯示“Song Rep XYW can't be empty”,這不好,因為該字段的標題不是用戶友好的。 如何更改字段本身的標題? 我可以更改數據庫中字段的實際名稱,但我有多個“歌曲”字段,我確實需要有特定的字段名稱。
我不想繞過 Rails 的驗證過程,我覺得應該有辦法解決這個問題。
現在,設置人性化名稱和自定義錯誤消息的公認方法是使用 locales 。
# config/locales/en.yml
en:
activerecord:
attributes:
user:
email: "E-mail address"
errors:
models:
user:
attributes:
email:
blank: "is required"
現在,“email”屬性的人性化名稱和存在驗證消息已更改。
可以為特定模型+屬性、模型、屬性或全局設置驗證消息。
在您的模型中:
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] %>
嘗試這個。
class User < ActiveRecord::Base
validate do |user|
user.errors.add_to_base("Country can't be blank") if user.country_iso.blank?
end
end
我在這里找到了這個。
Rails 3 到 6 的更新:
validate do |user|
user.errors.add(:base, "Country can't be blank") if user.country_iso.blank?
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
上面的代碼來自這里
是的,有一種方法可以在沒有插件的情況下做到這一點! 但它不像使用提到的插件那樣干凈和優雅。 這里是。
假設是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]
到目前為止,我們只顯示一條消息,總是針對第一個錯誤。 如果您想顯示所有錯誤,您可以在哈希中循環並顯示值。
希望有所幫助。
在自定義驗證方法中使用:
errors.add(:base, "Custom error message")
因為 add_to_base 已被棄用。
errors.add_to_base("Custom error message")
帶有完全本地化消息的 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"
我確認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
我建議安裝最初由 David Easley 編寫的custom_error_message gem (或作為插件)
它可以讓你做這樣的事情:
validates_presence_of :non_friendly_field_name, :message => "^Friendly field name is blank"
一種解決方案可能是更改 i18n 默認錯誤格式:
en:
errors:
format: "%{message}"
默認為format: %{attribute} %{message}
這是另一種方式:
如果您使用此模板:
<% 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 不能為空”
只需按照正常方式進行操作:
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."
這是我的代碼,如果您仍然需要它,它可能對您有用:我的模型:
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
如果您想將它們全部列在一個不錯的列表中,但又不使用粗俗的非人類友好名稱,您可以這樣做...
object.errors.each do |attr,message|
puts "<li>"+message+"</li>"
end
在你看來
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."
}
我試過以下,為我工作:)
1 份工作.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 %>
我從未見過任何人提及的獨特方法!
我能夠獲得我想要的所有自定義的唯一方法是使用after_validation
回調來允許我操縱錯誤消息。
允許正常創建驗證消息,您不需要嘗試在驗證助手中更改它。
創建一個after_validation
回調,該回調將在到達視圖之前替換后端中的驗證消息。
在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
如果在顯示字段名稱時實際區域設置不同,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 錯誤
升級后的@Federico 答案對所有字段錯誤都是通用的。
在您的controller.rb
:
flash[:alert] = @model.errors.messages.values
# [["field1_err1", "field1_err2"], ["field2_err1"], ["field3_err1"]]
messages
方法“返回 Hash 屬性及其錯誤消息數組”,如rails docs中所示。
然后,以表格形式顯示這些錯誤:
<% flash.each do |type, type_arr| %>
<% type_arr.each do |msg| %>
<ul>
<li>
<%= msg.to_sentence %>
</li>
</ul>
<% end %>
<% end %>
如果您正在使用Rails-5您還可以使用以下內容:
validates:user_name,presence:true,uniqueness:{message:“用戶名已存在。”}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.