Ответ 1
Я просто просмотрел проблемы github docrails, и они решили удалить f.error_messages, а не объяснять, как делать проверки для комментариев.
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
в последнем примере, но какую переменную я ссылаюсь в первом, чтобы получить сообщения об ошибках для создания комментариев?
Я просто просмотрел проблемы github docrails, и они решили удалить f.error_messages, а не объяснять, как делать проверки для комментариев.
Лучший и чистый способ реализовать 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
И все.
Я уверен, что все, что вам нужно сделать, это ссылка @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)
а затем прокрутите их в логике отображения, чтобы вывести каждую из ошибок комментариев.
Эта функциональность существует как автономный драгоценный камень 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
к вашим сборщикам форм.
Вот мое решение для всей сцены ошибок.
Я создал часть, которая просто использует переменную модели, которую она передавала бы при ее рендеринге:
<%# 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 %>
Мне нравится этот путь. Он прост, удобен в управлении/обслуживании и невероятно подстраивается.
Надеюсь, это поможет!
EDIT: все в 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
Я предполагаю, что массив [@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
к вопросу.