f.error_messages в Rails 3.0 - PullRequest
       0

f.error_messages в Rails 3.0

42 голосов
/ 06 октября 2010

Rails 3.0 устарела f.error_messages и теперь требует корректной работы плагина - однако я хочу научиться отображать сообщения об ошибках (новый) родным способом. Я следую руководству по началу работы , в котором при реализации формы комментариев используется устаревший метод. Например:

<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 в последнем примере, но на какую переменную я ссылаюсь в первом, чтобы получить сообщения об ошибках для создания комментария?

Ответы [ 6 ]

23 голосов
/ 29 октября 2010

Лучший и чистый способ реализации error_messages в вашей форме - это реализация error_messages в FormBuilder.

Например, вот метод 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

И это все.

13 голосов
/ 06 октября 2010

Я уверен, что все, что вам нужно сделать, это ссылка @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)

, а затем переберите их в логике отображения для вывода каждой ошибки комментария.

7 голосов
/ 06 ноября 2012

Эта функциональность существует как самостоятельный гем dynamic_form .

Добавьте следующее к вашему Gemfile

gem 'dynamic_form'

со страницы github :

DynamicForm содержит метод с несколькими помощниками, которые помогут вам разобраться с вашими моделями Rails3.

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

Он также добавляет f.error_messages и f.error_message_on к создателям форм.

3 голосов
/ 28 мая 2013

Вот мое решение всей сцены ошибки.

Я создал частичное, которое просто использует переменную модели, которую можно передать при рендеринге:

<%# 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-классы и / или имена идентификаторов, основанные как на имени модели, так и на общих.

У меня есть настройки, в которых мои сообщения об ошибках отображаются в одном и том же месте в файле макета:

<%# app/views/layouts/application.html.erb %>

<%= yield :message %>

Если кто-то не хочет этой функциональности, удаление content_for в частичном случае поможет.
Тогда на самом деле любой вид вы можете просто написать:

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

Можно дополнительно расширить это, создав частичное, которое принимает коллекцию и использует приведенную выше частичку ошибки:

<%# 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
1 голос
/ 06 октября 2010

Я предполагаю, что массив [@post, @post.comments.build] просто передается в polymorphic_path внутри form_for. Это создает путь подресурса для комментариев (например, /posts/1/comments в этом случае). Похоже, ваш первый пример использует комментарии в качестве подресурсов для сообщений, верно?

Так что на самом деле контроллер, который будет вызываться здесь - это CommentsController. Причина, по которой решение Lukas не работает для вас, может заключаться в том, что вы на самом деле не используете @ post.comments.build внутри контроллера при создании комментария (не имеет значения, что вы используете его в представлении при вызове form_for). Метод 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

Тогда вы можете использовать код, сгенерированный скаффолдингом, заменив только @post переменную экземпляра на @comment во всех строках, кроме вызова form_for.

Я думаю, что было бы также неплохо добавить @comment = @post.comment.build к методу контроллера, который отображает эту форму, и использовать form_for([@post, @comment], ...), чтобы содержимое формы отображалось в форме в случае ошибок.

Если это не сработает, и вы не можете в этом разобраться, пожалуйста, добавьте ваш метод CommentsController#create к вопросу.

0 голосов
/ 12 ноября 2010

Я только что посмотрел на проблемы с gocraub в docrails, и они решили удалить f.error_messages вместо того, чтобы объяснять, как выполнять проверку комментариев.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...