Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/54.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.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 如何在父模型的验证错误之后显示嵌套表单验证错误?_Ruby On Rails_Ruby On Rails 4_Nested Forms - Fatal编程技术网

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

Ruby on rails 如何在父模型的验证错误之后显示嵌套表单验证错误?,ruby-on-rails,ruby-on-rails-4,nested-forms,Ruby On Rails,Ruby On Rails 4,Nested Forms,使用RubyonRails4.2,我有一个嵌套的表单。在测试整个表单的验证时,我注意到嵌套表单的验证错误出现在验证错误列表的顶部,主表单的验证错误出现在下面 这与它们的声明顺序相反(因为的字段必须出现在的父表单的范围内),因此看起来如下所示: [name ] [description ] [others ] [nested #1 ] [nested #2 ] 但验证错误如下所示(使用blank作为示例验证错误): NestedModelName nested#

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

这与它们的声明顺序相反(因为的
字段必须出现在
的父
表单的范围内),因此看起来如下所示:

[name        ]
[description ]
[others      ]
[nested #1   ]
[nested #2   ]
但验证错误如下所示(使用blank作为示例验证错误):

  • NestedModelName nested#1不能为空
  • NestedModelName嵌套的#2不能为空
  • 名称不能为空
  • 说明不能为空
  • 其他人不能是空白的
这对于用户来说是令人困惑的,因为错误出现的顺序与它们在页面上的显示方式不一致。根据它在表单中出现的位置,它不希望它处于正确的位置,因为它显然只是依次验证每个模型,但由于嵌套表单模型通常是从属的,所以至少应该将它添加到末尾,而不是在开头显示。有没有办法让嵌套表单验证错误出现在父表单验证错误之后

其他信息:

使用以下命令在视图中显示错误:

应用程序\u helper.rb

def错误消息(资源)
如果resource.errors.empty为空,则返回“”?
messages=resource.errors.full_messages.map{| msg | content_标记(:li,msg)}.join
语句=I18n.t('errors.messages.not_saved',
计数:resource.errors.count,
资源:resource.class.model_name.human.downcase)

html=错误消息的顺序似乎反映了验证的顺序,
接受模型文件中
的嵌套属性。将验证按您希望的顺序进行,最后为
接受嵌套的属性。要获取您作为示例给出的订单,请尝试以下操作:

parent_model.rb

child_model.rb


每个散列中各个验证的顺序似乎也有影响,因为它改变了特定属性错误消息的显示顺序。

更新1

我发现,如果您不需要担心i18n和应用程序文本的翻译,那么二月的答案非常接近正确。如果将
has\u many:child\u模型
放在所有验证下面,验证将以正确的顺序显示。但是,
full_messages
似乎无法使用区域设置文件翻译模型或属性名称,因此,如果您需要翻译错误消息(我需要),我的答案似乎仍然是一个不错的解决方案

更新2:

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

app/models/parent_model.rb

app/models/child_model.rb

app/helpers/application_helper.rb

更新结束

我对
application\u helper.rb
中的
error\u messages
函数做了一些更改,现在一切都按我所希望的方式运行:主表单验证错误位于顶部,嵌套表单验证错误位于其下,除了将嵌套的表单错误移动到主表单错误下,错误的顺序不会更改

我的解决方案是更改
error\u messages
中的
messages=
行,如下所示,并添加一个私人助手方法。(为了便于阅读和理解,可能应该将其分解为多个部分,但我在控制台中构建了它以获得我想要的内容,并直接从那里粘贴)

app/helpers/application_helper.rb

此解决方案也适用于其他地区,因为我使用了
I18n
来获取所有名称。您还必须添加以下内容:

config/locales/en.yml

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

config/locales/zh.yml

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

例如,使用
en.yml
更改使用常见作者/书籍示例显示的姓名:

config/locales/en.yml

在本例中,如果没有上述添加到
en.yml
,默认值为:

  • 名称不能为空
  • 书名不能为空
  • 出版的书不能是空白的
但是在
en.yml
中添加上述内容后,它将是:

  • 名字不能为空
  • 稿件标题不能为空
  • 稿件年份不能为空
当然,如果您有一个带有适当翻译的
zh.yml
文件,那么这些文件中的任何内容都会显示出来

如果你不想
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) %>
...

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

accepts_nested_attributes_for :child_model

...
...

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

...
...

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

has_many :child_models
accepts_nested_attributes_for :child_models

...
...

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

...
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
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
en:
  space: " "
zh:
  space: ""
en:
  activerecord:
    models:
      author: "writer"
      book: "manuscript"
    attributes:
      author:
        name: "non de plume"
      book:
        name: "title"
        published: "year"
config.i18n.available_locales = [:zh, :en]
config.i18n.default_locale = :en