matiss
matiss

Reputation: 747

Rails 5: AJAX not triggering for save/load callbacks (PATCH / GET)

I'm a bit stuck in implementing AJAX with JSON response. I have this Controller

class Common::DatatablesStatesController < ApplicationController

  def update
    datatables_state.update(datatable_states_params)
    render json: datatables_state
  end

  def show
    render json: datatables_state
  end

  private
  def datatable_states_params
    params.require(:common_datatable_state).permit(:user_id, :name, :state)
  end

  def datatables_state
    @datatables_state ||= current_user.datatables_states
                          .where(name: params[:id]).first_or_create
  end
end

which basically checks if record by param exists if yes, then update state column, if no - creates new record (current_user ID, contname from JS below, state)

My Coffeescript at the moment looks like this:

$ ->
  $('#data-table').DataTable
    ajax: $('#data-table').data('source')
    serverSide: true
    stateSave: true
    contname = $('#data-table').attr('data-controller-name')
    'stateSaveCallback': (settings, data) ->
      $.ajax
        'url': '/common/datatables_states/' + contname + '.json'
        'data':
          'user_id': user_id
          'name': contname
          'state': data
        'dataType': 'json'
        'type': 'PATCH'
        success: ->
      return
    'stateLoadCallback': (settings, callback) ->
      $.ajax
        'url': '/common/datatables_states/' + contname + '.json'
        'data':
          'name': contname
          'state': data
        'async': false
        'dataType': 'json'
        'type': 'GET'
        'success': (json) ->
          callback json
          return
      return
  return

I'm pretty sure there is something wrong in my JS part as nothing is happening in my console, but don't know what it is. I'd be happy for any help. Thank you!

Update

My routes look like this:

namespace :common do
  resources :datatables_states, only: [:update, :show]
end

rails routes

 common_datatables_state GET    (/:locale)/common/datatables_states/:id(.:format)        common/datatables_states#show {:locale=>/en|lv/}
                                   PATCH  (/:locale)/common/datatables_states/:id(.:format)        common/datatables_states#update {:locale=>/en|lv/}
                                   PUT    (/:locale)/common/datatables_states/:id(.:format)        common/datatables_states#update {:locale=>/en|lv/}

Basically idea was to pass that data-controller-name from view as ID.

Update2

I switched to vanila JS as I had suspicion something's not right with my Coffeescript. Here is what I put in my JS file:

jQuery(document).ready(function() {
    $('#data-table').DataTable(
            {
                "processing": true,
                "serverSide": true,
                "ajax": $('#data-table').data('source'),
                stateSave: true,
                "stateSaveCallback": function (settings, data) {
                    // Send an Ajax request to the server with the state object
                    $.ajax( {
                        "url": "/common/datatables_states/campaigns_index.json", //Test link with :ID campaigns_index.json
                        "data": {"name":"campaigns_index", "state": data} ,
                        "dataType": "json",
                        "type": "PATCH",
                        "success": function () {}
                    } );
                },
                   stateLoadCallback: function (settings, callback) {
                      $.ajax( {
                         url: '/common/datatables_states/campaigns_index.json',
                         async: false,
                         dataType: 'json',
                         type: 'GET',
                         success: function (json) {
                         callback( json );
                         }
                    } );
                 }
            }
    );
});

and this is what I see in my console now:

Started PATCH "/common/datatables_states/campaigns_index.json" for 10.0.2.2 at 2017-05-12 20:27:03 +0000
Processing by Common::DatatablesStatesController#update as JSON
  Parameters: {"name"=>"campaigns_index", "state"=>{"time"=>"1494620823501", "start"=>"0", "length"=>"10", "order"=>{"0"=>["0", "asc"]}, "search"=>{"search"=>"", "smart"=>"true", "regex"=>"false", "caseInsensitive"=>"true"}, "columns"=>{"0"=>{"visible"=>"true", "search"=>{"search"=>"", "smart"=>"true", "regex"=>"false", "caseInsensitive"=>"true"}}, "1"=>{"visible"=>"true", "search"=>{"search"=>"", "smart"=>"true", "regex"=>"false", "caseInsensitive"=>"true"}}, "2"=>{"visible"=>"true", "search"=>{"search"=>"", "smart"=>"true", "regex"=>"false", "caseInsensitive"=>"true"}}}}, "id"=>"campaigns_index"}
  User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
  Common::DatatableState Load (1.5ms)  SELECT  "common_datatable_states".* FROM "common_datatable_states" WHERE "common_datatable_states"."user_id" = $1 AND "common_datatable_states"."name" = $2 ORDER BY "common_datatable_states"."id" ASC LIMIT $3  [["user_id", 2], ["name", "campaigns_index"], ["LIMIT", 1]]
Completed 400 Bad Request in 15ms (ActiveRecord: 2.0ms)


ActionController::ParameterMissing (param is missing or the value is empty: common_datatable_state):

app/controllers/common/datatables_states_controller.rb:14:in `datatable_states_params'
app/controllers/common/datatables_states_controller.rb:4:in `update'
app/controllers/application_controller.rb:45:in `set_current_user'

Update 3

I'm trying to implement stateLoadCallback for my DataTables 1.10.13.

I changed my controller action to this so it selects state only:

def show
  state = current_user.datatables_states.where(name: params[:id]).select(:state)
  render json: state
end

then in JS I do this, which is kind of according to docs:

 stateLoadCallback: function (settings, callback) {
                      $.ajax( {
                         url: '/common/datatables_states/campaigns_index.json',
                         async: false,
                         dataType: 'json',
                         type: 'GET',
                         success: function (json) {
                         callback( json );
                         }
                    } );
                 }

however in terminal I do not get state back:

Started GET "/common/datatables_states/campaigns_index.json" for 10.0.2.2 at 2017-05-14 10:02:03 +0000
Processing by Common::DatatablesStatesController#show as JSON
  Parameters: {"id"=>"campaigns_index"}
  User Load (0.9ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
  Common::DatatableState Load (1.6ms)  SELECT "common_datatable_states"."state" FROM "common_datatable_states" WHERE "common_datatable_states"."user_id" = $1 AND "common_datatable_states"."name" = $2  [["user_id", 2], ["name", "campaigns_index"]]
Completed 200 OK in 83ms (Views: 25.3ms | ActiveRecord: 9.6ms)

Type of my state column is JSON and when I navigate to http://localhost:3000/en/common/datatables_states/campaigns_index.json I see this:

[
  {
    "id": null,
    "state": "{\"time\":\"1494761473541\",\"start\":\"0\",\"length\":\"10\",\"order\":{\"0\":[\"0\",\"asc\"]},\"search\":{\"search\":\"\",\"smart\":\"true\",\"regex\":\"false\",\"caseInsensitive\":\"true\"},\"columns\":{\"0\":{\"visible\":\"true\",\"search\":{\"search\":\"\",\"smart\":\"true\",\"regex\":\"false\",\"caseInsensitive\":\"true\"}},\"1\":{\"visible\":\"true\",\"search\":{\"search\":\"\",\"smart\":\"true\",\"regex\":\"false\",\"caseInsensitive\":\"true\"}},\"2\":{\"visible\":\"true\",\"search\":{\"search\":\"\",\"smart\":\"true\",\"regex\":\"false\",\"caseInsensitive\":\"true\"}}}}"
  }
]

Update 3.1.

I added state = current_user.datatables_states.where(name: params[:id]).select(:state).first

and I have this now:

{
  "id": null,
  "state": "{\"time\":\"1494910215056\",\"start\":\"0\",\"length\":\"10\",\"order\":{\"0\":[\"0\",\"asc\"]},\"search\":{\"search\":\"\",\"smart\":\"true\",\"regex\":\"false\",\"caseInsensitive\":\"true\"},\"columns\":{\"0\":{\"visible\":\"true\",\"search\":{\"search\":\"\",\"smart\":\"true\",\"regex\":\"false\",\"caseInsensitive\":\"true\"}},\"1\":{\"visible\":\"true\",\"search\":{\"search\":\"\",\"smart\":\"true\",\"regex\":\"false\",\"caseInsensitive\":\"true\"}},\"2\":{\"visible\":\"true\",\"search\":{\"search\":\"\",\"smart\":\"true\",\"regex\":\"false\",\"caseInsensitive\":\"true\"}}}}"
}

When I change my show to this:

def show
  state = current_user.datatables_states.where(name: params[:id]).select(:state).first
  my_hash = JSON.parse(state)
  render json: JSON.pretty_generate(my_hash)
end

and get this error:

TypeError (no implicit conversion of nil into String):
app/controllers/common/datatables_states_controller.rb:10:in `show'
app/controllers/application_controller.rb:45:in `set_current_user'

What should I do to get my stateLoadCallback working?

Upvotes: 0

Views: 214

Answers (2)

xlts
xlts

Reputation: 136

The error you added indicates that no common_datatable_state parameter was passed, this is because of how you defined your strong parameters (datatable_state_params method). Try changing the data field in your ajax call like this:

"data": {"common_datatable_state":{"name":"campaigns_index", "state": data}}

Upvotes: 1

Rakesh
Rakesh

Reputation: 292

I think problem is here where(name: params[:id]) , could you check params here

Upvotes: 0

Related Questions