【问题标题】:f.error_messages in Rails 3.0Rails 3.0 中的 f.error_messages
【发布时间】:2011-04-21 20:27:57
【问题描述】:

Rails 3.0 已弃用 f.error_messages,现在需要一个插件才能正常工作 - 但是我想学习如何以(新)本机方式显示错误消息。我正在关注getting started guide,它在实现 cmets 表单时使用了已弃用的方法。例如:

<h2>Add a comment:</h2>
<%= form_for([@post, @post.comments.build]) do |f| %>
  <%= f.error_messages %>
<div class="field">
  <% f.label :commenter  %><br />
  <%= f.text_field :commenter  %>
</div>
<div class="field">
  <%= f.label :body %><br />
  <%= f.text_area :body %>
</div>
<div class="actions">
  <%= f.submit %>
</div>
<% end %>

这是正确的做法(由脚手架生成):

<%= form_for(@post) do |f| %>
  <% if @post.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>

      <ul>
      <% @post.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
 . . . 

我知道我在后一个示例中使用了@post 变量,但我在前一个示例中引用了什么变量来获取创建评论的错误消息?

【问题讨论】:

  • 你的问题是矛盾的。在这里,您询问如何在“前一个”示例中获取 cmets 的错误消息,这表明您正在询问 f.error_messages 的情况。 (或者您的意思是“形式”,而不是“形式”?)但是,在评论中,您问的是如何“不使用f.error_messages”获取错误消息。那么它是哪一个?

标签: ruby-on-rails ruby ruby-on-rails-3


【解决方案1】:

在表单中实现 error_messages 的最佳且简洁的方法是在 FormBuilder 中实现 error_messages。

例如,这是我为上一个项目实现的 error_messages 方法。 通过实现您自己的 FormBuilder,您可以遵循网页设计师的规则和样式... 这是一个示例,它将使用一些自定义样式输出 ul/li 中的错误列表:

class StandardBuilder < ActionView::Helpers::FormBuilder
  def error_messages
    return unless object.respond_to?(:errors) && object.errors.any?

    errors_list = ""
    errors_list << @template.content_tag(:span, "There are errors!", :class => "title-error")
    errors_list << object.errors.full_messages.map { |message| @template.content_tag(:li, message) }.join("\n")

    @template.content_tag(:ul, errors_list.html_safe, :class => "error-recap round-border")
  end
end

然后在我的表格中:

= f.error_messages

仅此而已。

【讨论】:

  • 嗨 Nicolas,我可以添加这个 FormBuilder 吗?
  • 仍然不适合我。我将代码剪切并粘贴到一个新文件 app/helpers/standard_builder.rb 中,但我的表单上的 给出了错误“未定义的方法 `error_messages' for #<:helpers: :formbuilder:0x45ceef8>"。我是否必须做其他事情才能使其可用?
  • 谢谢,我发现为了完成这项工作,我还必须在 application_helper.rb 中执行以下操作: ActionView::Base.default_form_builder = StandardBuilder(参见 alexreisner.com/code/form-builders-in-rails
【解决方案2】:

我很确定您需要做的就是参考 @post.comments

所以你可以这样做:

<% @post.comments.each do |comment| %>
    <% if comment.errors.any? %>

    <% comment.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
    <% end %>

    <% end %>
<% end %>

或者只是把所有的错误都拉出来:

comment_errors = @post.comments.map(&:errors)

然后在显示逻辑中循环它们以输出每个注释错误。

【讨论】:

  • 感谢您的尝试,但不,这不起作用。也许更简单的提问方式是“如何在不使用“f.error_messages”的情况下显示评论错误,而不是使用“[@post,@post.cmets.build]”而不是像@post 这样简单的东西?
  • 老实说,我从未见过有人这样做form_for([@post, @post.comments.build])。而是一直是form_for(@post) do |p|,然后是p.fields_for(@post.comments.build) do |c|。所以你可以考虑在帖子表单内部使用字段吗?
  • 嗯,实际上是“Rails - 入门”指南的做法。
【解决方案3】:

此功能作为独立 gem dynamic_form 存在。

将以下内容添加到您的Gemfile

gem 'dynamic_form'

来自github page

DynamicForm 包含一些帮助方法来帮助您处理 Rails3 模型,它们是:

  • input(record, method, options = {})
  • form(record, options = {})
  • error_message_on(object, method, options={})
  • error_messages_for(record, options={})

它还会将f.error_messagesf.error_message_on 添加到您的表单构建器中。

【讨论】:

    【解决方案4】:

    这是我对整个错误场景的解决方案。

    我创建了一个部分,它只使用一个模型变量,在渲染它时会传递它:

    <%# app/views/errors/_error.html.erb %>
    
    <%= content_for :message do %>
      <% if model.errors.any? %>
        <ul>
          <% model.errors.full_messages.each do |msg| %>
            <li><%= msg %></li>
          <% end %>
        </ul>
      <% end %>
    <% end %>
    

    您可以根据模型名称轻松添加动态 html 类和/或 id 名称,以及通用名称。

    我设置了一些东西,我的错误消息在布局文件中的所有相同位置呈现:

    <%# app/views/layouts/application.html.erb %>
    
    <%= yield :message %>
    

    如果不想要该功能,删除部分中的 content_for 就可以解决问题。
    然后在你想要的任何视图中,你都可以简单地写:

    <%= render 'errors/error', model: @some_model %>
    

    人们可以通过创建一个partial来进一步扩展它,它接受一个集合并利用上面的error partial:

    <%# app/views/errors/_collection.html.erb %>
    
    <% collection.each do |model| %>
      <%= render 'errors/error', model: model %>
    <% end %>
    

    渲染它:

    <%= render 'errors/collection', collection: @some_model.some_has_many_association %>
    

    我喜欢这种方式。它简单、易于管理/维护,并且非常易于调整。
    我希望这会有所帮助!

    编辑:HAML 中的一切

    -# app/views/errors/_error.html.haml
    
    = content_for :message do
      - if model.errors.any?
        %ul
          - model.errors.full_messages.each do |msg|
            %li= msg
    


    -# app/views/layouts/application.html.haml
    
    = yield :message
    


    = render 'errors/error', model: @some_model
    


    -# app/views/errors/_collection.html.haml
    
    - collection.each do |model|
      = render 'errors/errors', model: @some_model
    


    = render 'errors/_collection', collection: @some_model.some_has_many_association
    

    【讨论】:

    • 我是新手,我发现它很混乱,如果可能的话,你能发布代码的 github 链接吗?
    • @Am33d 如果我有空闲时间编写一个基本的 Rails 应用程序来演示这个功能,我会告诉你的。您对我创建的内容有什么具体问题吗?哪个部分令人困惑?
    【解决方案5】:

    我猜[@post, @post.comments.build] 数组只是传递给form_for 内部的polymorphic_path。这会为 cmets 生成一个子资源路径(如本例中的 /posts/1/comments)。所以看起来您的第一个示例使用 cmets 作为帖子的子资源,对吗?

    所以实际上这里将调用的控制器是CommentsController。 Lukas 的解决方案对您不起作用的原因可能是您在创建评论时实际上没有在控制器内部使用 @post.cmets.build (调用 @ 时在视图中使用它并不重要) 987654326@)。 CommentsController#create 方法应该看起来像这样(或多或少):

    def create
      @post = Post.find(params[:post_id]
      @comment = @post.comments.build(params[:comment])
    
      if(@comment.save)
        # you would probably redirect to @post
      else
        # you would probably render post#show or wherever you have the form
      end
    end
    

    然后就可以使用脚手架生成的代码了,只需要在除form_for调用之外的所有行中将@post实例变量替换为@comment即可。

    我认为将@comment = @post.comment.build添加到显示此表单的控制器方法中并使用form_for([@post, @comment], ...)保持表单内容显示在表单中也是一个好主意。如果有错误。

    如果这不起作用并且您无法弄清楚,请将您的 CommentsController#create 方法添加到问题中。

    【讨论】:

      【解决方案6】:

      我刚刚查看了 docrails github 问题,他们决定删除 f.error_messages 而不是解释如何对 cme​​ts 进行验证。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-23
        • 2011-07-28
        • 1970-01-01
        • 2011-11-07
        • 2011-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多