Ruby on Rails:如何从显示的子资源中获取错误消息?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2680016/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ruby on Rails: how to get error messages from a child resource displayed?
提问by randombits
I'm having a difficult time understanding how to get Rails to show an explicit error message for a child resource that is failing validation when I render an XML template. Hypothetically, I have the following classes:
我很难理解如何让 Rails 在呈现 XML 模板时为未通过验证的子资源显示显式错误消息。假设,我有以下课程:
class School < ActiveRecord::Base
has_many :students
validates_associated :students
def self.add_student(bad_email)
s = Student.new(bad_email)
students << s
end
end
class Student < ActiveRecord::Base
belongs_to :school
validates_format_of :email,
:with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i,
:message => "You must supply a valid email"
end
Now, in the controller, let's say we want to build a trivial API to allow us to add a new School with a student in it (again, I said, it's a terrible example, but plays its role for the purpose of the question)
现在,在控制器中,假设我们想要构建一个简单的 API 以允许我们添加一个包含学生的新学校(我再说一遍,这是一个糟糕的例子,但在问题中发挥了作用)
class SchoolsController < ApplicationController
def create
@school = School.new
@school.add_student(params[:bad_email])
respond_to do |format|
if @school.save
# some code
else
format.xml { render :xml => @school.errors, :status => :unprocessable_entity }
end
end
end
end
Now the validation is working just fine, things die because the email doesn't match the regex that's set in the validates_format_of method in the Student class. However the output I get is the following:
现在验证工作正常,事情会死,因为电子邮件与 Student 类中 validates_format_of 方法中设置的正则表达式不匹配。但是我得到的输出如下:
<?xml version="1.0" encoding="UTF-8"?>
<errors>
<error>Students is invalid</error>
</errors>
I want the more meaningful error message that I set above with validates_format_of to show up. Meaning, I want it to say:
我希望显示我上面使用 validates_format_of 设置的更有意义的错误消息。意思是,我想说:
<error>You must supply a valid email</error>
What am I doing wrong for that not to show up?
我做错了什么才没有出现?
回答by Harish Shetty
Add a validation block in the Schoolmodel to merge the errors:
在School模型中添加验证块以合并错误:
class School < ActiveRecord::Base
has_many :students
validate do |school|
school.students.each do |student|
next if student.valid?
student.errors.full_messages.each do |msg|
# you can customize the error message here:
errors.add_to_base("Student Error: #{msg}")
end
end
end
end
Now @school.errorswill contain the correct errors:
现在@school.errors将包含正确的错误:
format.xml { render :xml => @school.errors, :status => :unprocessable_entity }
Note:
笔记:
You don't need a separate method for adding a new student to school, use the following syntax:
您不需要单独的方法将新学生添加到学校,请使用以下语法:
school.students.build(:email => email)
Update for Rails 3.0+
Rails 3.0+ 的更新
errors.add_to_basehas been dropped from Rails 3.0 and above and should be replaced with:
errors.add_to_base已从 Rails 3.0 及更高版本中删除,应替换为:
errors[:base] << "Student Error: #{msg}"
回答by Quv
This is not a public API yet, but Rails 5 stable seems to have ActiveModel::Errors#copy!to merge errorsbetween two models.
这还不是公共 API,但 Rails 5 stable 似乎必须在两个模型之间ActiveModel::Errors#copy!进行合并errors。
user = User.new(name: "foo", email: nil)
other = User.new(name: nil, email:"[email protected]")
user.errors.copy!(other.errors)
user.full_messages #=> [ "name is blank", "email is blank" ]
Again, this is not officially published yet (I accidentally find this one before monkey-patching Errorsclass), and I'm not sure it will be.
同样,这还没有正式发布(我在猴子补丁Errors课之前偶然发现了这个),我不确定它会是。
So it's up to you.
所以这取决于你。
回答by Ashish Agrawal
Update Rails 5.0.1
更新 Rails 5.0.1
You can use Active Record Autosave Association
您可以使用 Active Record 自动保存关联
class School < ActiveRecord::Base
has_many :students, autosave: true
validates_associated :students
end
class Student < ActiveRecord::Base
belongs_to :school
validates_format_of :email,
:with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i,
:message => "You must supply a valid email"
end
@school = School.new
@school.build_student(email: 'xyz')
@school.save
@school.errors.full_messages ==> ['You must supply a valid email']
reference: http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html
参考:http: //api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html
回答by Kubee
I'm not sure if this is the best (or a correct) answer...i'm still learning, but I found this to work pretty well. I haven't tested it extensively, but it does seem to work with rails4:
我不确定这是否是最好的(或正确的)答案......我仍在学习,但我发现这很有效。我还没有对其进行广泛的测试,但它似乎可以与 rails4 一起使用:
validate do |school|
school.errors.delete(:students)
school.students.each do |student|
next if student.valid?
school.errors.add(:students, student.errors)
end
end
回答by Chris Cashwell
Here's an example that could stand some DRYing:
这是一个可以承受一些干燥的示例:
def join_model_and_association_errors!(model)
klass = model.class
has_manys = klass.reflect_on_all_associations(:has_many)
has_ones = klass.reflect_on_all_associations(:has_one)
belong_tos = klass.reflect_on_all_associations(:belongs_to)
habtms = klass.reflect_on_all_associations(:has_and_belongs_to_many)
collection_associations = [has_manys, habtms].flatten
instance_associations = [has_ones, belong_tos].flatten
(collection_associations + instance_associations).each do |association|
model.errors.delete(association.name)
end
collection_associations.each do |association|
model.send(association.name).each do |child|
next if child.valid?
errors = child.errors.full_messages
model.errors[:base] << "#{association.class_name} Invalid: #{errors.to_sentence}"
end
end
instance_associations.each do |association|
next unless child = model.send(association.name)
next if child.valid?
errors = child.errors.full_messages
model.errors[:base] << "#{association.class_name} Invalid: #{errors.to_sentence}"
end
model.errors
end
回答by Salil
You should use following in the rhtml.
您应该在 rhtml 中使用以下内容。
<%= error_messages_for :school, :student %>
To skip "Students is invalid" message use following in the student.rb
要跳过“学生无效”消息,请在 student.rb 中使用以下消息
def after_validation
# Skip errors that won't be useful to the end user
filtered_errors = self.errors.reject{ |err| %w{ student}.include?(err.first) }
self.errors.clear
filtered_errors.each { |err| self.errors.add(*err) }
end
EDITED
已编辑
Sorry after_validation must be in a school.rb
回答by Fred
I see a problem in the posted code. add_studentis a class method of class School, so selfwill point to the class object Schoolinstead of an instance object of class School. The line students << swill not add the record sto the record schoolbecause of this.
我在发布的代码中看到了一个问题。 add_student是类的类方法School,所以self会指向类对象School而不是类的实例对象School。因此,该行students << s不会将记录添加s到记录school中。
I don't know if this is causing your error message problem, but I think this will keep the code from working properly.
我不知道这是否会导致您的错误消息问题,但我认为这会使代码无法正常工作。
回答by Yi Feng Xie
I have the same issue. no good answer so far. So I solved it by myself. by replacing association error message with detail error message:
我有同样的问题。到目前为止没有好的答案。所以我自己解决了。通过用详细错误消息替换关联错误消息:
create a concern file models/concerns/association_error_detail_concern.rb:
创建一个关注文件models/concerns/association_error_detail_concern.rb:
module AssociationErrorDetailConcern
extend ActiveSupport::Concern
included do
after_validation :replace_association_error_message
end
class_methods do
def association_names
@association_names ||= self.reflect_on_all_associations.map(&:name)
end
end
def replace_association_error_message
self.class.association_names.each do |attr|
next unless errors[attr]
errors.delete(attr)
Array.wrap(public_send(attr)).each do |record|
record.errors.full_messages.each do |message|
errors.add(attr, message)
end
end
end
end
end
in your model:
在您的模型中:
class School < ApplicationRecord
include AssociationErrorDetailConcern
has_many :students
...
end
then you will get you must supply a valid emailerror message on studentsattribute of schoolrecord. instead of useless message is invalid
那么您将收到有关记录属性的you must supply a valid email错误消息。而不是无用的消息studentsschoolis invalid

