How to display error messages in a multi-model form with transaction?

后端 未结 5 1265
长情又很酷
长情又很酷 2021-01-23 06:53

Two models, Organization and User, have a 1:many relationship. I have a combined signup form where an organization plus a user for that organization get signed up.

The p

相关标签:
5条回答
  • 2021-01-23 07:17

    Did you code successfully create a person during the rescue block?

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

    This code looks like it will create a new empty User regardless of incorrect validations. And render new will simply return no errors because the user was successfully created, assuming Organization has no Users.

    The control flow of this method has a few outcomes, definitely needs to be broken down some more. I would use byebug and walk through the block with an incorrect Organization, then incorrect name. Then an empty Organization with incorrect User attributes.

    0 讨论(0)
  • 2021-01-23 07:22

    This is very related to this question. The key is that <%= render 'shared/error_messages', object: f.object %> is, I assume, only calling the .errors method on the object it is passed (in this case, organization).

    However, because the user errors reside with the user object, they won't be returned and therefore will not be displayed. This requires simply changing the view logic to also display the results of .errors on the various user models. How you want to do so is up to you. In the linked thread, the accepted answer had the error message display code inline instead of in a partial, so you could do it that way, but it would be somewhat redundant.

    I would modify my shared/error_messages.html.erb file to check for another passed local called something like nested_models. Then it would use that to search the associated models and include the errors on that. We just would need to check whether it is defined first so that your other views that don't have a nested model won't cause it to raise an error.

    shared/error_messages.html.erb

    <% if object.errors.any? %>
      <div class="error-messages">
        Object Errors:
        <ul>
          <% object.errors.full_messages.each do |msg| %>
            <li><%= msg %></li>
          <% end %>
        </ul>
        <% if defined?(nested_models) && nested_models.any? %>
          Nested Model(s) Errors:
          <ul>
            <% nested_models.each do |nested_model| %>
              <% unless nested_model.valid? %>
                <li>
                  <ul>
                    <% nested_model.errors.full_messages.each do |msg| %>
                      <li><%= msg %></li>
                    <% end %>
                  </ul>
                </li>
              <% end %>
            <% end %>
          </ul>
        <% end %>
      </div>
    <% end %>
    

    Then you would just need to change a single line in your view:

    <%= render partial: 'shared/error_messages', locals: { object: @organization, nested_models: @organization.users } %>
    
    0 讨论(0)
  • 2021-01-23 07:29

    organization has_many :users and user belongs_to :organization

    organization.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 %>
    

    In controller

    def create
      @organization = Organization.new(new_params)
      if @organization.save
        flash[:success] = "Yeah!"
        redirect_to root_url
      else
       render :new
      end
    end
    
    0 讨论(0)
  • 2021-01-23 07:29

    Looks like you have a lot of untestable logic in your controller. Looks like for you logic will be better to use simple FormObject pattern. https://robots.thoughtbot.com/activemodel-form-objects

    0 讨论(0)
  • 2021-01-23 07:30

    Try adding validates_associated :users under your has_many :users association in Organization.

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

    0 讨论(0)
提交回复
热议问题