¿Cómo mostrar los mensajes de error en un formulario de varios modelos con transacción?

Dos modelos, Organización y Usuario, tienen una relación 1: muchos. Tengo un formulario de registro combinado en el que se registra una organización más un usuario para esa organización.

El problema que estoy experimentando es: al enviar información no válida para el usuario, se vuelve a presentar el formulario como debería, pero no se muestran los mensajes de error (como “el nombre de usuario no puede estar en blanco”) para el usuario. El formulario funciona cuando se envía información válida y muestra mensajes de error para la organización, pero no para el usuario.

¿Cómo debo ajustar el código a continuación para que también se muestren los mensajes de error para el usuario?

def new @organization = Organization.new @user = @organization.users.build end def create @organization = Organization.new(new_params.except(:users_attributes)) #Validations require the organization to be saved before user, since user requires an organization_id. That's why users_attributs are above excluded and why below it's managed in a transaction that rollbacks if either organization or user is invalid. This works as desired. @organization.transaction do if @organization.valid? @organization.save begin # I executed next line in debugger (with invalid user info), which correctly responds with: ActiveRecord::RecordInvalid Exception: Validation failed: Email can't be blank, Email is invalid, Username can't be blank, etc. @organization.users.create!(users_attributes) rescue # Should I perhaps add some line here that adds the users errors to the memory? raise ActiveRecord::Rollback end end end if @organization.persisted? flash[:success] = "Yeah!" redirect_to root_url else @user = @organization.users.build(users_attributes) # Otherwise the filled in information for user is gone (fields for user are then empty) render :new end end 

La vista de formulario incluye:

    # Other fields   # Other fields    

Los mensajes de error parciales son los siguientes:

  
  • Actualización: Siguiendo los pasos de la respuesta de Rob, llegué a los errores parciales a continuación. Esto todavía no muestra mensajes de error para el usuario. Agregué respuestas de depurador dentro del código a continuación y, por alguna razón, nested_model.errors.any? devuelve falso, mientras que el depurador dentro del controlador (ver arriba) devuelve mensajes de error para el usuario.

      
    The form contains .
    # Debugger: responds with "local-variable" for "defined?(nested_models)" and for "nested_models.any?" returns true.
      # Debugger: "nested_model" has the same values as "nested_models.any?", as you would expect. But for "nested_model.errors.any?" it returns false, which it shouldn't. #Initially had "unless nested_model.valid?" but then errors for User are immediately displayed on loading the form page (new method).

    Intente agregar validates_associated :users bajo su has_many :users asociación de has_many :users en Organización.

    http://apidock.com/rails/ActiveModel/Validations/ClassMethods/validates_associated

    ¿Codificaste exitosamente la creación de una persona durante el bloque de rescate?

      rescue ActiveRecord::RecordInvalid => exception # do something with exception here raise ActiveRecord::Rollback @organization.users.build if @organization.users.blank? render :new and return 

    Parece que este código creará un nuevo usuario vacío independientemente de las validaciones incorrectas. Y generar nuevo simplemente no devolverá errores porque el usuario se creó con éxito, asumiendo que la Organización no tiene Usuarios.

    El flujo de control de este método tiene algunos resultados, definitivamente necesita ser desglosado un poco más. Usaría Byebug y recorrería el bloque con una Organización incorrecta, luego un nombre incorrecto. Entonces una organización vacía con atributos de usuario incorrectos.

    organizacion has_many: usuarios y usuario pertenece_a: organizacion

    organización.rb

     accepts_nested_attributes_for :users 

    new.html.erb

     <%= form_for @organization, url: next_url do |f| %> <%= render 'shared/error_messages', object: @organization %> <%= f.text_field :name %> # Other fields <%= f.fields_for(:users,@organization.users.build) do |p| %> <%= p.email_field :email %> # Other fields <% end %> <%= f.submit "Submit" %> <% end %> 

    En el controlador

     def create @organization = Organization.new(new_params) if @organization.save flash[:success] = "Yeah!" redirect_to root_url else render :new end end 

    Esto está muy relacionado con esta pregunta . La clave es que <%= render 'shared/error_messages', object: f.object %> es, supongo, solo llamar al método .errors en el objeto que se pasa (en este caso, organization ).

    Sin embargo, debido a que los errores del user residen en el objeto del user , no se devolverán y, por lo tanto, no se mostrarán. Esto requiere simplemente cambiar la lógica de vista para mostrar también los resultados de .errors en los distintos modelos de user . Cómo quieras hacerlo depende de ti. En el hilo enlazado, la respuesta aceptada tenía el código de visualización del mensaje de error en línea en lugar de una parcial, por lo que podría hacerlo de esa manera, pero sería algo redundante.

    Me gustaría modificar mi archivo shared/error_messages.html.erb para buscar otro local llamado algo nested_models como nested_models . Luego lo usaría para buscar los modelos asociados e incluir los errores en eso. Solo tendríamos que comprobar si está definido primero para que sus otras vistas que no tienen un modelo nested no generen un error.

    shared / error_messages.html.erb

     <% if object.errors.any? %> 
    Object Errors:
      <% object.errors.full_messages.each do |msg| %>
    • <%= msg %>
    • <% end %>
    <% if defined?(nested_models) && nested_models.any? %> Nested Model(s) Errors:
      <% nested_models.each do |nested_model| %> <% unless nested_model.valid? %>
      • <% nested_model.errors.full_messages.each do |msg| %>
      • <%= msg %>
      • <% end %>
    • <% end %> <% end %>
    <% end %>
    <% end %>

    Entonces solo necesitarías cambiar una sola línea en tu vista:

     <%= render partial: 'shared/error_messages', locals: { object: @organization, nested_models: @organization.users } %> 

    Parece que tienes mucha lógica no comprobable en tu controlador. Parece que para usted la lógica será mejor usar un patrón simple de FormObject. https://robots.thoughtbot.com/activemodel-form-objects