ruby-on-railsajaxturbolinksrails-ujs

rails ujs call on subset of class


Class Usercontent has records being generated and shown via AJAX calls with turbolinks, essentially the rails way, aside from jQuery3 being invoked in a rails 5 app.

However there are two rendering cases, one for all objects of the class (usercontent), another for a subset (point), on the same page, but in tabs, with two distinct forms and the following usercontents.js javascript.

$(document).on('turbolinks:load', function() {
  $('[data-js-usercontent-form]').on("ajax:success", function(event, data, status, xhr){
    var usercontent = $(xhr.responseText).hide();
    $('#usercontents').append(usercontent);
    usercontent.fadeIn(1000);
  });

  $('[data-js-usercontent-id]').on("ajax:success", function(event, data, status, xhr){
    var usercontent_id = xhr.responseJSON.id;
    $('[data-js-usercontent-id=' + usercontent_id + ']').hide();
  });
  $('[data-js-point-form]').on("ajax:success", function(event, data, status, xhr){
    var point = $(xhr.responseText).hide();
    $('#points').append(point);
    point.fadeIn(1000);
  });    

  $('[data-js-point-id]').on("ajax:success", function(event, data, status, xhr){
    var point_id = xhr.responseJSON.id;
    $('[data-js-point-id=' + point_id + ']').hide();
  });
});

the controller declares the two collections

@usercontents = Usercontent.all
@points = Usercontent.where(['contenttype_id = ?', 1]).all

the view has two distinct calls to the collections

<div id=points class='tableize'>
  <%= render @points %>

<div id=usercontents class='tableize'>
  <%= render @usercontents %>

who in turn call the individual item to be updated via AJAX _point.html.erb (both partials are in the views/usercontents directory)

<div class='row' data-js-point-id=<%= point.id %>>

and _usercontent.html.erb

<div class='row' data-js-usercontent-id=<%= usercontent.id %>>

The problem is the former renders the 'full' collection with the wrong data-js call :

<div id="points" class="tableize">
  <div class="row" data-js-usercontent-id="33"></div>
  <div class="row" data-js-usercontent-id="34"></div>
  <div class="row" data-js-usercontent-id="35"></div>
  <div class="row" data-js-usercontent-id="36"></div>
  <div class="row" data-js-usercontent-id="37"></div>
  <div class="row" data-js-usercontent-id="38"></div>
  <div class="row" data-js-usercontent-id="39"></div>
  <div class="row" data-js-usercontent-id="48"></div>
</div>

Clearly render @points is not rendering properly. How can this be fixed?


Solution

  • Your problem is because:

    Rails determines the name of the partial to use by looking at the model name in the collection.
    (source)

    which means your partial _point.html.erb is never used.

    The @points collection is rendered within the _usercontent.html.erb because it contains Usercontent records.

    To fix your issue, render the partial by pointing the right context:

    <div id=points class='tableize'>
      <%= render partial: "point", collection: @points %>