ruby-on-rails - que - ruby on rails tutorial
f.error_messages en Rails 3.0 (6)
Rails 3.0 ha f.error_messages
y ahora requiere un complemento para que funcione correctamente. Sin embargo, quiero aprender a mostrar los mensajes de error de la (nueva) forma nativa. Estoy siguiendo la guía de introducción , que usa el método en desuso al implementar el formulario de comentarios. Por ejemplo:
<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 %>
Esta es la forma correcta de hacerlo (según lo generado por el andamio):
<%= 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 %>
. . .
Entiendo que utilizo la variable @post
en el último ejemplo, pero ¿a qué variable hago referencia en el primero para obtener los mensajes de error para la creación de comentarios?
Acabo de analizar los problemas de github de doralos, y han decidido eliminar los mensajes f.error en lugar de explicar cómo hacer la validación para los comentarios.
Aquí está mi solución para toda la escena de error.
Creé un parcial que simplemente usa una variable de modelo que pasaría al renderizarlo:
<%# 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 %>
Puede agregar fácilmente una clase html dinámica y / o nombres de identificación basados en el nombre del modelo, así como en los genéricos.
Tengo las cosas configuradas donde mis mensajes de error se muestran en el mismo lugar en un archivo de diseño:
<%# app/views/layouts/application.html.erb %>
<%= yield :message %>
Si uno no quiere esa funcionalidad, eliminar el content_for en el parcial sería el truco.
Entonces, en realidad, cualquier punto de vista que desee puede simplemente escribir:
<%= render ''errors/error'', model: @some_model %>
Uno podría expandir esto creando un parcial que toma una colección y aprovecha el error parcial arriba:
<%# app/views/errors/_collection.html.erb %>
<% collection.each do |model| %>
<%= render ''errors/error'', model: model %>
<% end %>
Renderizarlo con:
<%= render ''errors/collection'', collection: @some_model.some_has_many_association %>
Me gusta de esta manera. Es simple, fácil de administrar / mantener, e increíblemente modificable.
¡Espero que esto ayude!
EDITAR: Todo en 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
Esta funcionalidad existe como una gema independiente dynamic_form .
Agregue lo siguiente a su Gemfile
gem ''dynamic_form''
De la dynamic_form :
DynamicForm contiene algunos métodos de ayuda para ayudarle a manejar sus modelos de Rails3, estos son:
-
input(record, method, options = {})
-
form(record, options = {})
-
error_message_on(object, method, options={})
-
error_messages_for(record, options={})
También agrega f.error_messages
y f.error_message_on
a los creadores de formularios.
Estoy bastante seguro de que todo lo que necesitarías hacer es consultar @post.comments
Entonces podrías hacer algo como:
<% @post.comments.each do |comment| %>
<% if comment.errors.any? %>
<% comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>
<% end %>
O simplemente saque todos los errores:
comment_errors = @post.comments.map(&:errors)
y luego recorrerlos en su lógica de visualización para generar cada uno de los errores de comentario.
La mejor y más limpia forma de implementar error_messages en su formulario es implementando error_messages en FormBuilder.
Por ejemplo, aquí está el método error_messages que implementé para mi último proyecto. Implementando su propio FormBuilder puede seguir las reglas y estilos de su diseñador web ... Aquí hay un ejemplo que mostrará la lista de errores en ul / li''s con algunos estilos personalizados:
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
Entonces en mis formas:
= f.error_messages
Y eso es todo.
Supongo que la [@post, @post.comments.build]
acaba de pasar a polymorphic_path
dentro de form_for
. Esto genera una ruta de sub-recursos para comentarios (como /posts/1/comments
en este caso). Entonces, parece que su primer ejemplo usa comentarios como sub-recursos para las publicaciones, ¿verdad ?.
Así que en realidad el controlador que se llamará aquí es el CommentsController
. La razón por la cual la solución de Lukas no funciona para usted podría ser que en realidad no use @ post.comments.build dentro del controlador al crear el comentario (no importa que lo use en la vista cuando llame a form_for
) El método CommentsController#create
debería verse así (más o menos):
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
Luego puede usar el código generado por el andamiaje, solo reemplace @post
variable de instancia con @comment
en todas las líneas, excepto form_for
call.
Creo que también puede ser una buena idea agregar @comment = @post.comment.build
al método del controlador que muestra este formulario y usar form_for([@post, @comment], ...)
para mantener el contenido del formulario se muestra en el formulario si hay errores.
Si esto no funciona y no puede resolverlo, agregue su método CommentsController#create
a la pregunta.