如何在父模型的验证错误之后显示嵌套表单验证错误?

2024-01-20

使用 Ruby on Rails 4.2,我有一个嵌套表单。在测试整个表单的验证时,我注意到嵌套表单的验证错误出现在验证错误列表的顶部,而主表单的验证错误出现在下面。

这与它们的声明顺序相反(因为fields_for必须出现在父级的范围内form_for),所以它看起来像这样:

[name        ]
[description ]
[others      ]
[nested #1   ]
[nested #2   ]

但验证错误看起来像这样(使用空白作为示例验证错误):

  • NestedModelName 嵌套 #1 不能为空。
  • NestedModelName 嵌套 #2 不能为空。
  • 名称不能为空。
  • 描述不能为空。
  • 其他不能为空。

这会让用户感到困惑,因为错误的显示顺序与它们在页面上的显示顺序不符。它并不期望它根据它在表单中出现的位置处于正确的位置,因为它显然只是依次验证每个模型,但由于嵌套表单模型通常是从​​属的,因此至少应该将其添加到结束而不是在开始时出现。有没有办法让嵌套表单验证错误出现在父表单验证错误之后?

附加信息:

使用以下内容在视图中显示错误:

application_helper.rb

def error_messages(resource)

    return '' if resource.errors.empty?

    messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
    sentence = I18n.t('errors.messages.not_saved',
                      count: resource.errors.count,
                      resource: resource.class.model_name.human.downcase)
    html = <<-HTML
    <div class="validation-error alert alert-danger alert-dismissable fade in alert-block">
      <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
      <p>#{sentence}</p>
      <ul>
        #{messages}
      </ul>
    </div>
    HTML

  end

并在包含表单的每个视图文件中使用它:

<%= error_messages(@model) %>

Update 1:

我发现如果您不需要担心 i18n 和应用程序文本的翻译,februaryInk 的答案非常接近正确。如果你把has_many :child_model 您的所有验证,验证将以正确的顺序显示。然而,full_messages似乎没有使用区域设置文件来翻译模型或属性名称,因此如果您需要翻译错误消息(我确实这样做),我的答案似乎仍然是一个不错的解决方案。

更新2:

在发布第一次更新后刚刚意识到我可以简化生成的代码messages通过删除使用更新 1 中的发现进行排序的部分来列出很多内容,并只保留进行翻译的部分。这是我的新解决方案,它是我的更新 1 和原始解决方案的组合。有关的所有其他信息config/locales/xx.yml and config/application.rb对于此更新的解决方案,文件仍然与原始解决方案相同。

应用程序/模型/parent_model.rb

...

validates :name, # validations hash
validates :description, # validations hash
validates :others, # validations hash

has_many :child_models
accepts_nested_attributes_for :child_models

...

应用程序/模型/child_model.rb

...

validates :nested_1, # validations hash
validates :nested_2, # validations hash

...

应用程序/helpers/application_helper.rb

messages = resource.errors.messages.keys.map {|value| error_message_attribute(resource, value) + I18n.t('space') + resource.errors.messages[value].first}.map { |msg| content_tag(:li, msg) }.join

private
  def error_message_attribute(resource, symbol)
    if symbol.to_s.split(".").length > 1
      model_name, attribute_name = symbol.to_s.split(".")
      model_class = model_name.singularize.camelize.constantize
      model_class.model_name.human + I18n.t('space') + model_class.human_attribute_name(attribute_name).downcase
    else
      resource.class.human_attribute_name(symbol)
    end
  end

更新结束

我对我的进行了一些更改error_messages函数于application_helper.rb现在一切都按我想要的方式工作:主表单验证错误位于顶部,嵌套表单验证错误位于其下方,除了将嵌套表单错误移至主表单错误下外,错误的顺序不会改变。

我的解决方案是改变messages =线路输入error_messages如下所示并添加一个私有帮助器方法。 (这可能应该分为几个部分,以便于阅读和理解,但我在控制台中构建了它以获得我想要的内容,然后直接从那里粘贴)。

应用程序/helpers/application_helper.rb

messages = Hash[resource.errors.messages.keys.map.with_index(1) { |attribute, index| [attribute, [index, attribute.match(/\./) ? 1 : 0]] }].sort_by {|attribute, data| [data[1], data[0]]}.collect { |attributes| attributes[0]}.map {|value| error_message_attribute_name(resource, value) + I18n.t('space') + resource.errors.messages[value].first}.map { |msg| content_tag(:li, msg) }.join

private
    def error_message_attribute_name(resource, symbol)
      if symbol.to_s.split(".").length > 1
        model_name, attribute_name = symbol.to_s.split(".")
        model_class = model_name.singularize.camelize.constantize
        model_class.model_name.human + I18n.t('space') + model_class.human_attribute_name(attribute_name).downcase
      else
        resource.class.human_attribute_name(symbol)
      end
    end

该解决方案也应该适用于其他其他语言环境,因为我使用了I18n得到所有的名字。您还必须添加以下内容:

配置/语言环境/en.yml

en:
  space: " "

这样,模型和属性名称就可以在单词之间有或没有空格的语言中正确处理(我需要支持的第一个语言环境是中文,单词之间没有空格)。例如,如果您确实需要支持中文,您可以使用以下命令:

配置/语言环境/zh.yml

zh:
  space: ""

如果您不必支持这种情况,则所有实例I18n.t('space')可以替换为" "。模型和属性名称也可以翻译为,但同样,如果您不需要支持英语以外的语言环境,则无需执行任何操作(尽管您可以使用en.yml文件来更改显示的模型或属性的名称)。

作为一个例子使用en.yml使用常见的作者/书籍示例更改显示的名称:

配置/语言环境/en.yml

en:
  activerecord:
    models:
      author: "writer"
      book: "manuscript"
    attributes:
      author:
        name: "non de plume"
      book:
        name: "title"
        published: "year"

本例中默认,没有上面的添加en.yml, 将会:

  • 名称不能为空。
  • 书名不能为空。
  • 出版的书不能为空。

但有了上面的补充en.yml这将是:

  • 羽毛名称不能为空。
  • 稿件标题不能为空。
  • 稿件年份不能为空。

当然,如果你有一个zh.yml文件中包含适当的翻译,其中的任何内容都会显示出来。

如果您确实需要支持多个区域设置,请不要忘记将以下内容添加到config/application.rb(这部分只是进行了表面测试,可能还需要一些额外的配置):

配置/应用程序.rb

config.i18n.available_locales = [:zh, :en]
config.i18n.default_locale = :en
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在父模型的验证错误之后显示嵌套表单验证错误? 的相关文章

  • 如何使用哈希数组填充 select_tag?

    在 Rails 3 2 应用程序中 我尝试添加一个选择字段 该字段从外部 API 调用获取数据 该数据作为哈希数组返回 name gt NameA id gt 001 name gt NameB id gt 002 我如何使用这些数据来构造
  • 为什么这个 rspec 请求规范不更新模型?

    我有一个与用户模型交互的请求规范 我想确保具有管理员角色的用户可以创建 编辑 销毁用户 我现在遇到一个问题 编辑操作无法更新用户 当我手动执行网站本身的操作时 一切正常 但测试无法更新用户 这是我的规格 it edits a user do
  • Rails (PostgreSQL) 中文本列的默认大小

    如果我在迁移中有这个 t text body 我可以容纳多少文字 body 如果相关的话我正在使用 PostgreSQL 直接来自PostgreSQL 文档 http www postgresql org docs 8 4 static d
  • Ruby on Rails:如何检查复数形式和单一形式的名称

    我用命令创建了一个匿名模型 rails g model Anonymous section id integer aid string fake bool active bool 但迁移中的表名称为匿名 class CreateAnonym
  • 如何在Rails中管理没有id的表?

    我有两个模型 人模型和关系模型 第二个存储有关两个人之间关系的信息 它有parent id和child id字段 但没有id字段 我将它与 has many through 连接起来并且它有效 But 即使表中存在某些关系 因为没有 id
  • Rails 命令有什么区别:--no-test-framework、--skip-test-unit 和 -T?

    原本我以为这三者都是一样的 但现在仔细一看 却发现它们各有不同 我通过搜索找不到任何关于此的好的文档 根据导轨API http api rubyonrails org classes Rails Generators Base html a
  • jQuery Datepicker showAnim 没有动画

    我尝试了多种方法并在互联网上搜索 试图让动画发挥作用 但一无所获 我有日期选择器工作和日期格式选项 但没有动画 我希望使用 剪辑 选项 以下是各个文件中的内容 应用程序 js require jquery require jquery tu
  • jQuery 自动完成滚动问题

    我在用着Rails3 jquery 自动完成 https github com crowdint rails3 jquery autocomplete在我的应用程序中 我遇到了以下问题 如果您在输入字段中输入某些内容以便显示自动完成数据并在
  • 在多个模型中与 has_many :through 建立关联

    请帮助了解该怎么做 project payments有这棵树 Project Stages Costs Payments 项目 rb has many stages has many costs through gt stages stag
  • 初始化会破坏rails中的布局设置吗?

    在其中一个控制器中 我需要特定的布局 我添加了layout一开始 效果很好 但如果我添加一个initialize某些基于控制器的变量的函数 Rails 似乎只是忽略了layout命令 有人有同样的问题吗 我该如何修复它 class Admi
  • 在 git 中管理 schema.rb 的首选方法是什么?

    我不想添加schema rb to gitignore 因为我希望能够从该文件加载新的数据库架构 然而 保持检查状态会导致各种虚假冲突 而这些冲突很容易通过新的解决方案解决 db migrate reset 基本上我想要一种方法 将 sch
  • 列“users.id”必须出现在 GROUP BY 子句中或在聚合函数中使用

    关系 Item belongs to Product Product belongs to User 项目型号范围 scope search gt search term select products name users product
  • 从轨道控制器返回

    这是一个初学者 Rails 问题 我这样做之后 format xml head ok 如何从控制器端点返回而不显示视图 如果我此时放弃函数的末尾 我会得到我所期望的结果 但如果我调用 返回 我最终会进入视图 或者在我的情况下会出现缺少的视图
  • 带分页的 Rails 随机活动记录

    我需要查找特定资源的所有记录并以随机顺序显示它们 但具有一致的分页 如果开始分页 您将不会看到相同的记录两次 每次用户访问页面时 显示顺序都应该是随机的 我在用将分页 http wiki github com mislav will pag
  • 如何访问“可以?”细胞内的方法?

    我在用着cancan and cells我的 ruby on rails 项目中的 gems 如何访问can 细胞内的方法 Thanks 我必须这样做 尝试 class MyCell lt Cell Rails include CanCan
  • 安装 Rails Apartment gem 时出现问题

    当我尝试时出现错误 bundle exec rails generate apartment install 收到此错误 build Apartment Reloader 的未定义方法新 字符串 无方法错误 看起来这是一个中间件问题 任何解
  • Rails:验证字符串的最小和最大长度,但允许其为空白

    我有一个想要验证的字段 我希望该字段能够留空 但如果用户输入数据 我希望它采用某种格式 目前我在模型中使用以下验证 但这不允许用户将其留空 validates length of foo maximum gt 5 validates len
  • 如何在保存父对象时确保子对象有效?

    假设我有两堂课 class User attr accessible name has one address validates name presence gt true validates associated address end
  • Rails & Devise:如何在没有布局的情况下呈现登录页面?

    我知道这可能是一个简单的问题 但我仍在试图弄清楚Devise https github com plataformatec devise out 我想要render layout gt false在我的登录页面上 我怎样才能做到这一点Dev
  • RuntimeError:无法修改冻结的数组(Rollbar、Rails 5.1 升级)

    升级到rails 5后无法使用rspec和rollbar 创建 Rails 4 应用程序 升级 gemfile 以使用 Rails 5 尝试添加防滚杆 gem support 标准配置 环境 rb Load the Rails applic

随机推荐