Tra*_*ago 32 validation ruby-on-rails
Rails显示与给定字段关联的所有验证错误消息.如果我有三个validates_XXXXX_of :email,并且我将该字段留空,我会在错误列表中收到三条消息.
例:
validates_presence_of :name
validates_presence_of :email
validates_presence_of :text
validates_length_of :name, :in => 6..30
validates_length_of :email, :in => 4..40
validates_length_of :text, :in => 4..200
validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i<br/>
Run Code Online (Sandbox Code Playgroud)
<%= error_messages_for :comment %> 给我:
7 errors prohibited this comment from being saved
There were problems with the following fields:
Name can't be blank
Name is too short (minimum is 6 characters)
Email can't be blank
Email is too short (minimum is 4 characters)
Email is invalid
Text can't be blank
Text is too short (minimum is 4 characters)
Run Code Online (Sandbox Code Playgroud)
最好一次显示一条消息.有没有一种简单的方法来解决这个问题?看起来很简单:如果您发现了错误:email,请停止验证:email并跳至其他字段.
rza*_*zar 34
[Update] Jan/2013 to Rails 3.2.x - update syntax; add spec
Inspired by new validation methods in Rails 3.0 I'm adding this tiny Validator. I call it ReduceValidator.
lib/reduce_validator.rb:
# show only one error message per field
#
class ReduceValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return until record.errors.messages.has_key?(attribute)
record.errors[attribute].slice!(-1) until record.errors[attribute].size <= 1
end
end
Run Code Online (Sandbox Code Playgroud)
我的模型看起来像 - 请注意:reduce => true:
validates :title, :presence => true, :inclusion => { :in => %w[ Mr Mrs ] }, :reduce => true
validates :firstname, :presence => true, :length => { :within => 2..50 }, :format => { :without => /^\D{1}[.]/i }, :reduce => true
validates :lastname, :presence => true, :length => { :within => 2..50 }, :format => { :without => /^\D{1}[.]/i }, :reduce => true
Run Code Online (Sandbox Code Playgroud)
就像我目前的Rails项目中的魅力一样.有利的是,我把验证器只放在几个字段上,而不是全部.
spec/lib/reduce_validator_spec.rb:
require 'spec_helper'
describe ReduceValidator do
let(:reduce_validator) { ReduceValidator.new({ :attributes => {} }) }
let(:item) { mock_model("Item") }
subject { item }
before(:each) do
item.errors.add(:name, "message one")
item.errors.add(:name, "message two")
end
it { should have(2).error_on(:name) }
it "should reduce error messages" do
reduce_validator.validate_each(item, :name, '')
should have(1).error_on(:name)
end
end
Run Code Online (Sandbox Code Playgroud)
小智 16
Imo简化是:
<% @model.errors.each do |attr, msg| %>
<%= "#{attr} #{msg}" if @model.errors[attr].first == msg %>
<% end %>
Run Code Online (Sandbox Code Playgroud)
Nat*_*ray 11
在RailsForum的 Bert 过了一会儿写了这篇文章.他编写了下面的代码,并添加了一些小调整,以便在Rails-3.0.0-beta2上运行.
将其添加到名为的文件中app/helpers/errors_helper.rb,只需添加helper "errors"到控制器即可.
module ErrorsHelper
# see: lib/action_view/helpers/active_model_helper.rb
def error_messages_for(*params)
options = params.extract_options!.symbolize_keys
objects = Array.wrap(options.delete(:object) || params).map do |object|
object = instance_variable_get("@#{object}") unless object.respond_to?(:to_model)
object = convert_to_model(object)
if object.class.respond_to?(:model_name)
options[:object_name] ||= object.class.model_name.human.downcase
end
object
end
objects.compact!
count = objects.inject(0) {|sum, object| sum + object.errors.count }
unless count.zero?
html = {}
[:id, :class].each do |key|
if options.include?(key)
value = options[key]
html[key] = value unless value.blank?
else
html[key] = 'errorExplanation'
end
end
options[:object_name] ||= params.first
I18n.with_options :locale => options[:locale], :scope => [:errors, :template] do |locale|
header_message = if options.include?(:header_message)
options[:header_message]
else
locale.t :header, :count => count, :model => options[:object_name].to_s.gsub('_', ' ')
end
message = options.include?(:message) ? options[:message] : locale.t(:body)
error_messages = objects.sum do |object|
object.errors.on(:name)
full_flat_messages(object).map do |msg|
content_tag(:li, ERB::Util.html_escape(msg))
end
end.join.html_safe
contents = ''
contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
contents << content_tag(:p, message) unless message.blank?
contents << content_tag(:ul, error_messages)
content_tag(:div, contents.html_safe, html)
end
else
''
end
end
####################
#
# added to make the errors display in a single line per field
#
####################
def full_flat_messages(object)
full_messages = []
object.errors.each_key do |attr|
msg_part=msg=''
object.errors[attr].each do |message|
next unless message
if attr == "base"
full_messages << message
else
msg=object.class.human_attribute_name(attr)
msg_part+= I18n.t('activerecord.errors.format.separator', :default => ' ') + (msg_part=="" ? '': ' & ' ) + message
end
end
full_messages << "#{msg} #{msg_part}" if msg!=""
end
full_messages
end
end
Run Code Online (Sandbox Code Playgroud)