Liz
Liz

Reputation: 1437

Rails AJAX Not Rendering Partial

I have a form to create a new source on sources#create on which there is a modal to create a new author. The user can either create a new author to assign to the source or select an existing one from a checklist.

Ideally, if they do need to create a new author, the authors#create form would create the author AJAX-ically and the new author would appear automatically on the checklist of authors that can be associated to the source.

Here is the code for the author selection checkboxes on sources#create:

  <section id="author" class="white h-100">

    <h2>Author(s)</h2>

    <% if @user_authors.count != 0 %>
      <p class="text-center">Select an author to add below or <a data-toggle="modal" data-target="#newAuthorModal">create a new author</a>.</p>
      <div id="#authorsChecklist"><%= render partial: "authors/checklist", locals: { f: f } %></div>
    <% else %>
      <p class="text-center"><a data-toggle="modal" data-target="#newAuthorModal">Create a New Author</a></p>
    <% end %>

  </section>

With this as the authors/_checklist.html.erb partial:

<div class="boxed-scroll">
  <%= f.collection_check_boxes :author_ids, @user_authors.sort_by(&:last_name), :id, :last_first do |b| %>
    <div class="field form-check" style="display: block">
      <%= b.check_box class: "form-check-input" %>
      <%= b.label class: "form-check-label" %>
    </div>
  <% end %>
</div> <!-- boxedscroll -->

And this as the modal to create the author:

<!-- New Author Modal -->
<div class="modal fade" id="newAuthorModal" tabindex="-1" role="dialog" aria-labelledby="newAuthorModalLabel"
  aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="newAuthorModalLabel">Add a New Author</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <%= render partial: "authors/js_form", locals: {author: @new_author} %>
      </div>
    </div>
  </div>
</div>

And here's the create method:

  def create
    @author = Author.new(author_params)
    @author.user_id = current_user.id

    respond_to do |format|
      if @author.save
        format.html { redirect_back(fallback_location: author_path(@author)) }
        format.json { render :show, status: :created, location: @author }
        format.js
      else
        format.html { render :new }
        format.json { render json: @author.errors, status: :unprocessable_entity }
      end
    end
  end

And here's authors/create.js:

  $("#authorsChecklist").html("<%= escape_javascript(render partial: 'authors/checklist', locals: { f: f } ) %>"); 

So far the author does get created successfully:

Started POST "/authors" for ::1 at 2020-01-31 21:23:26 -0800
Processing by AuthorsController#create as JS
  Parameters: {"utf8"=>"✓", "author"=>{"first_name"=>"Liz", "middle_initials"=>"", "last_name"=>"Bayardelle", "notes"=>""}, "commit"=>"Save Author Info"}
  User Load (1.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/application_controller.rb:5
   (0.1ms)  BEGIN
  ↳ app/controllers/authors_controller.rb:32
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/authors_controller.rb:32
  Author Create (0.8ms)  INSERT INTO "authors" ("first_name", "middle_initials", "last_name", "notes", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"  [["first_name", "Liz"], ["middle_initials", ""], ["last_name", "Bayardelle"], ["notes", ""], ["user_id", 1], ["created_at", "2020-02-01 05:23:26.279449"], ["updated_at", "2020-02-01 05:23:26.279449"]]
  ↳ app/controllers/authors_controller.rb:32
   (0.4ms)  COMMIT
  ↳ app/controllers/authors_controller.rb:32
  Rendering authors/create.js
  Rendered authors/create.js (0.4ms)
Completed 200 OK in 214ms (Views: 27.8ms | ActiveRecord: 42.7ms)

However, the modal doesn't go away when you hit submit and the author doesn't get added to the checkboxes list (basically the partial doesn't refresh). When you manually hit refresh the author appears perfectly.

Can anyone see how to get this to AJAX properly? The desired behavior is for the modal to disappear when you hit submit and for the checklist partial to AJAX-ically refresh so the author appears.

UPDATE

As per comment suggestions, I added this to the create.js, which successfully makes the modal disappear, though the partial did not refresh:

$('#newAuthorModal').modal('hide');

I then found this question which revealed I needed to change create.js to create.js.erb. This somehow stopped the modal from disappearing but yielded a server error saying:

NameError - undefined local variable or method `f' for #<#<Class:0x00007f9e1e0c0ad0>:0x00007f9e18101d38>:
  app/views/authors/create.js.erb:2:in `_app_views_authors_create_js_erb__3387754959944580247_70158492637620'

SECOND UPDATE

After consulting the documentation for collection_check_boxes, the f. before collection_check_boxes is not necessary. I removed it and removed , locals: { f: f } from my create.js.erb. The modal now dismisses properly and the error is gone, but I still have to hit refresh to get the name to appear.

Upvotes: 3

Views: 476

Answers (1)

Liz
Liz

Reputation: 1437

In sources#create there was a typo:

<div id="#authorsChecklist">

Should have been:

<div id="authorsChecklist">

And the controller method needed to include the definition of @user_authors:

format.js do
   @user_authors = Author.where(user_id: current_user.id)
end

Now it works!

Upvotes: 2

Related Questions