Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails RubyonRails:如何从显示的子资源获取错误消息?_Ruby On Rails_Ruby_Activerecord_Rest - Fatal编程技术网

Ruby on rails RubyonRails:如何从显示的子资源获取错误消息?

Ruby on rails RubyonRails:如何从显示的子资源获取错误消息?,ruby-on-rails,ruby,activerecord,rest,Ruby On Rails,Ruby,Activerecord,Rest,我很难理解如何让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 e

我很难理解如何让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
班级学校“您必须提供有效的电子邮件”
结束
现在,在控制器中,让我们假设我们想要构建一个简单的API,允许我们添加一个新的学校,其中有一个学生(同样,我说过,这是一个糟糕的例子,但在问题中扮演了它的角色)

class-SchoolsController@school.errors,:status=>:unprocessable_entity}
结束
结束
结束
结束
现在验证工作正常了,因为电子邮件与学生类中validates\u format\u方法中设置的正则表达式不匹配,所以一切都会消失。但是,我得到的输出如下:

<?xml version="1.0" encoding="UTF-8"?>
<errors>
  <error>Students is invalid</error>
</errors>

学生是无效的
我想显示我在上面用validates\u format\u设置的更有意义的错误消息。意思是,我想说:

 <error>You must supply a valid email</error>
您必须提供有效的电子邮件

我做了什么错事让它不出现

您应该在rhtml中使用以下命令

<%= error_messages_for :school, :student %>
已编辑

Sorry after_validation must be in a school.rb

我在发布的代码中看到一个问题
add_student
是class
School
的类方法,因此
self
将指向class对象
School
,而不是class
School
的实例对象。行
students在
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
注意:

向学校添加新学生不需要单独的方法,请使用以下语法:

school.students.build(:email => email)
Rails 3.0的更新+
错误。已从Rails 3.0及更高版本中删除“将\添加到\基础”
,应替换为:

errors[:base] << "Student Error: #{msg}"

errors[:base]我不确定这是否是最好(或正确)的答案……我仍在学习,但我发现这很有效。我还没有对它进行过广泛的测试,但它似乎确实适用于Rails 4:

validate do |school|
  school.errors.delete(:students)
  school.students.each do |student|
    next if student.valid?
    school.errors.add(:students, student.errors)
  end
end

下面是一个可以经受一些干燥的示例:

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
def join_model_和_association_错误!(模型)
klass=model.class
has_manys=klass.反思所有关联(:has_many)
has_ones=klass。反映所有关联(:has_one)
归属=klass。反映所有关联(:归属)
habtms=klass。反映所有关联(:has_和属于许多)
集合\u关联=[has\u manys,habtms]。展平
实例\关联=[有\个,属于\ tos]。展平
(集合关联+实例关联)。每个集合关联|
model.errors.delete(association.name)
结束
集合|关联。每个do |关联|
model.send(association.name)|
下一个如果child.valid?
errors=child.errors.full_消息

model.errors[:base]这还不是一个公共API,但Rails 5 stable似乎有
ActiveModel::errors#copy
在两个模型之间合并
错误

user=user.new(名称:“foo”,电子邮件:nil)
其他=用户。新建(名称:无,电子邮件:foo@bar.com")
user.errors.copy!(其他.错误)
user.full_messages#=>[“名称为空”,“电子邮件为空”]
同样,这篇文章还没有正式发表(我在monkey patching
Errors
class之前意外地发现了这篇文章),我不确定它会不会发表

所以这取决于你

更新Rails 5.0.1

您可以使用活动记录自动保存关联

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']
班级学校/^([^@\s]+)@((?:[-a-z0-9]+\)+[a-z]{2,})$/i,
:message=>“您必须提供有效的电子邮件”
结束
@学校
@学校。建筑学生(电子邮件:“xyz”)
@学校储蓄
@school.errors.full_messages==>[“您必须提供有效的电子邮件”]

参考资料:

我也有同样的问题。到目前为止还没有好的答案。 所以我自己解决了。通过将关联错误消息替换为详细错误消息:

创建关注点文件
模型/关注点/关联\u错误\u详细信息\u关注点.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
在您的模型中:

class School < ApplicationRecord
  include AssociationErrorDetailConcern
  has_many :students
  ...
end
班级学校

然后您将获得
您必须在
学校
记录的
学生
属性上提供有效的电子邮件
错误消息。在XML模板中执行此操作的最佳方法是什么?现在我没有一个XML视图,我只是让render来处理它,它被链接并存储到数据库中。正如问题最初所暗示的那样,我故意通过发送一封不好的电子邮件而使验证失败。如果我发送了一封通过正则表达式的正确电子邮件,那么我就不会收到错误。这里的要点是故意失败,并在视图中获得适当的信息。我知道您故意失败了示例。我想你不明白我的意思。为什么要将add_student方法作为class方法?在Ruby中,self指向class方法中的class对象,因此消息add_student在发送到实例对象时,执行时self指向class对象而不是实例对象。尽管如此,也许ActiveRecord成功地做了正确的事情,但除非我遗漏了什么,否则该方法应该
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']
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
class School < ApplicationRecord
  include AssociationErrorDetailConcern
  has_many :students
  ...
end