Rails – ActionView :: Base.field_error_proc向上移动DOM树?

无论如何从传入的html_tag元素上升DOM树?

ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| # implementation end 

无论如何我可以实现这个方法来提升DOM树并在父div上放置一个类吗?

例如:

  

我想在div.email上放一个类,而不是直接在输入/标签上放置一些东西。

这可以使用field_error_proc方法完成还是有一个干净的替代方案?

我想避免在每个表单字段的视图中明确地这样做。 (如下)

 .email{:class => object.errors[:email].present? 'foo' : nil} =form.label :email =form.text_field :email 

仅供参考:对我的问题的简短回答是,无法在field_error_proc方法中访问DOM的其他部分。 这是因为这些方法实际上并没有构建DOM,而只是将一堆字符串连接在一起。 有关可能的解决方法的信息,请阅读以下解决方案。

你有两个选择,我可以想到我的头脑:

重写ActionView :: Base.field_error_proc

在一种情况下,我重写了ActionView :: Base.field_error_proc(它上面有一个rails)。 使用一点nokogiri,我更改了proc,将错误消息添加到input / textarea元素的data-error属性,而不是将它们包装在错误div中。 然后使用jquery编写了一个小javascript来将所有输入及其标签包装在文档就绪上。 如果存在与输入/ textarea关联的错误信息,则将其传送到包装器div。

我知道这个解决方案依赖于javascript,并且可能有也可能没有优雅的回退,但它在我的情况下工作正常,因为它适用于Web应用程序而不是可公开访问的站点。 我认为在那种情况下需要javascript。

 # place me inside your base controller class ActionView::Base.field_error_proc = Proc.new do |html_tag, object| html = Nokogiri::HTML::DocumentFragment.parse(html_tag) html = html.at_css("input") || html.at_css("textarea") unless html.nil? css_class = html['class'] || "" html['class'] = css_class.split.push("error").join(' ') html['data-error'] = object.error_message.join(". ") html_tag = html.to_s.html_safe end html_tag end 

编写自己的ActionView :: Helpers :: FormBuilder

您还可以通过覆盖text_field方法获得或多或少相同的效果,以便它始终返回包装的输入。 然后,使用对象变量,访问错误哈希并将任何所需的错误信息添加到包装器。 这个不需要javascript并且运行良好,但最后我更喜欢第一种方法,因为我发现它更灵活。 但是,如果我在一个可公开访问的网站上工作,我会使用这种方法。

另外,仅供参考,我发现覆盖check_box和radio_button方法很方便,因此它们总是返回带有相关标签的输入。 使用自定义FormBuilder可以做很多有趣的事情。

 # place me inside your projects lib folder class PrettyFormBuilder < ActionView::Helpers::FormBuilder def check_box(field, label_text, options = {}) checkbox = super(field, options) checkbox += label(field, label_text) @template.content_tag(:div, checkbox, :class => "wrapper") end end 

上面的示例显示了如何包装check_box,但它与text_field大致相同。 就像我说的,如果需要,使用object.errors来访问错误哈希。 这只是冰山的一角……你可以用自定义的FormBuilders做很多事。

如果您转到自定义表单构建器路由,您可能会发现修改上面的ActionView :: Base.field_error_proc非常有用,因此在出现错误时不会获得双重包装字段。

 ActionView::Base.field_error_proc = Proc.new do |html_tag, object| html_tag # return the html tag unmodified and unwrapped end 

要使用表单构建器,请在form_for方法调用中指定它,或将以下内容放在应用程序助手中:

 # application helper module ApplicationHelper ActionView::Base.default_form_builder = PrettyFormBuilder end 

通常我的解决方案最终使用每种解决方案的一些组合来实现期望的结果。