Railsowe "link_to" wywoływane z funkcji JS ...and Datatables.net

Witajcie po świętach :smile:

Postanowiłem się trochę ruszyć po tych świętach i …usiadłem do kompa :smiley:

Zaczynam “lizać” trochę JavaScript i w projekcie użyłem datatables.
Działa OK.
Zamiast stosować jednak w kolumnach linki (tak aby wywołać np Show dla określonego wiersza), chcę zrobić “link” taki, że klikając w dowolne miejsce w określonym wierszu, wykona się ta operacja show.

Napisałem zatem:

var otable = $('#companies').DataTable({
......
columns: [
  {
    "targets": [0],
    "title": "ID",
    "visible": false,
    "searchable": false,
    "sortable": false
  },
....
})


$('#companies tbody').on('click', 'tr', function () {
    var rowId = otable.row( this ).data()[0];
    var newurl = window.location.protocol + '//' + window.location.host + '/companies/' + rowId;
    window.location.href = newurl;
  });

Dodam, że kolumna “0” jest kolumną ukrytą i zawiera comany.id, czyli
rowId = otable.row( this ).data()[0]; daje mi moje “id”

Działa to dobrze i wywołuje przykładowe:
http://127.0.0.1:3000/companies/13205

ale moim pytaniem jest, czy konstrukcja:

var newurl = window.location.protocol + '//' + window.location.host + '/companies/' + rowId;
window.location.href = newurl;

jest “elegancka”, czy też inaczej byście to zrobili?

Imo data-url w tr

Piszesz do “zielonego” człowieka. :wink:
Czy możesz napisać to od A do Z ?

Nooo doobra.

<tr data-url="<%= link_to company_path(company) %>">

$('#companies tbody').on('click', 'tr', function () {
  window.location.href = $(this).data('url');
});

dziękulska :slight_smile:

Chyba nie będę zakładał nowego tematu, gdyż mój problem nadal dotyczy datatables.net

Mam w jej definicji sporą ilość kolumn (14 w tym 2 ukryte) i oczywiście pojawia się błąd:

[2015-01-21 23:48:45] ERROR WEBrick::HTTPStatus::RequestURITooLarge
[2015-01-21 23:48:45] ERROR TypeError: can’t convert nil into an exact number

Bardzo zależy mi, by nie usuwać kolumn z tabeli. Ograniczenie ich ilości oczywiście usuwa ten błąd ale czy można coś zrobić z tym fantem, by jednak zachować je wszystkie?

Jest pomysł, by dodać webrick.rb w config\initializers i zwiększyć MAX_URI_LENGTH

if defined?(WEBrick::HTTPRequest)
  WEBrick::HTTPRequest.const_set("MAX_URI_LENGTH", 10240)
end

enter link description here

ale już mi tłumaczono, że zwiększanie tego parametru nie jest najlepszym pomyslem.

A Wy macie jakieś dobre pomysły?

Fajnie by było jakbyś pokazał kawałek JS który wywołuje AJAX’a (jeśli w ogóle dobrze się domyślam o co chodzi, bo dość enigmatycznie opisałeś swój problem). Prawdopodobnie możesz przekazać wszystko w body zamiast w url’u (i poustawiać dobre nagłówki, ale ciężko zgadywać)

1 Like

OK…

GemFile

gem 'jquery-datatables-rails',  github: 'rweng/jquery-datatables-rails'
gem 'ajax-datatables-rails', git: 'git://github.com/antillas21/ajax-datatables-rails.git', branch: 'master'

route.rb

  resources :insurances do
    resources :groups, controller: 'insurances/groups' 
  end

insurances/groups_controller.rb

class Insurances::GroupsController < ApplicationController
  before_action :authenticate_user!

  def index
    respond_to do |format|
      format.html
      format.json{ render json: InsuranceGroupsDatatable.new(view_context, { only_for_current_insurance_id: @insurance.id }) }
    end
  end
....
end

views/insurances/groups/_index.html.erb

  <table id="insurance-groups" class="compact hover order-column cell-border"  data-source="<%= insurance_groups_path(@insurance.id, format: :json) %>">
    <thead>
      <tr>
        <th>0 id</th>
        <th>1 insurance_id</th>
        <th>2 </th>
        <th>3 </th>
        <th>4 </th>
        <th>5 </th>
        <th>6 </th>
        <th>7 </th>
        <th>8 </th>
        <th>9 </th>
        <th>10 </th>
        <th>11 </th>
        <th>12 </th>
        <th>13 </th>
        <th>14 </th>
      </tr>
    </thead>

    <tbody>
       <!--data from JSON -->
    </tbody>
  </table>

assets/javascrips/groups.js.erb

$(document).ready(function() {
  var oInsuranceGroupstable = $('#insurance-groups').DataTable({
    responsive: true,
    processing: true,
    serverSide: true,
    ajax: $('#insurance-groups').data('source'),    
    pagingType: "full_numbers",
    lengthMenu: [[10, 15, 25, 50, 100, -1], [10, 15, 25, 50, 100, "Wszystkie"]],
    "order": [[ 2, "asc" ]],
    columns: [
      { "targets": [0],
        "title": "ID",
        "visible": false,
        "searchable": false,
        "sortable": false }, 
      { "targets": [1],
        "title": "INSURANCE_ID",
        "visible": false,
        "searchable": false,
        "sortable": false },
      { "targets": [2],
        "title": "Nr" }, 
      { "targets": [3],
        "title": "Kwotacja" }, 
      { "targets": [4],
        "title": "System świadczeń" }, 
      { "targets": [5],
        "title": "Zakres" }, 
      { "targets": [6],
        "title": "Grupa ryzyka" },
      { "targets": [7],
        "title": "Świadczenie" }, 
      { "targets": [8],
        "title": "Leczenie" }, 
      { "targets": [9],
        "title": "Zasiłek ambulat." }, 
      { "targets": [10],
        "title": "Szpital" }, 
      { "targets": [11],
        "title": "Zawał" }, 
      { "targets": [12],
        "title": "Niezdolność" }, 
      { "targets": [13],
        "title": "Śmierć 100%" }, 
      { "targets": [14],
        "title": "Roczna za osobę" }
    ],
    language: {
      decimal:        ",",
      thousands:      " ",
      //processing: "<img src='/assets/spinner.gif'>",
      processing:     "<img src='<%= asset_path('spinner.gif') %>'>",
      lengthMenu:     "Pokaż _MENU_ pozycji",
      info:           "Pozycje od _START_ do _END_ z _TOTAL_ łącznie",
      infoEmpty:      "Pozycji 0 z 0 dostępnych",
      infoFiltered:   "(filtrowanie spośród _MAX_ dostępnych pozycji)",
      infoPostFix:    "",
      search:         "Szukaj&nbsp;:",
      loadingRecords: "Wczytywanie...",
      zeroRecords:    "Nie znaleziono pasujących pozycji",
      emptyTable:     "Brak danych",
      paginate: {
        first:      "<<",
        previous:   "<",
        next:       ">",
        last:       ">>"
      }
    }
  });
});

i ostatni wg przykładu

datatables/insurance_groups_datatable.rb

class InsuranceGroupsDatatable < AjaxDatatablesRails::Base
  # uncomment the appropriate paginator module,
  # depending on gems available in your project.
  include AjaxDatatablesRails::Extensions::Kaminari
  # include AjaxDatatablesRails::Extensions::WillPaginate
  # include AjaxDatatablesRails::Extensions::SimplePaginator

  def_delegators :@view, :link_to, :h, :mailto

  def sortable_columns
    # list columns inside the Array in string dot notation.
    # Example: 'users.email'
    @sortable_columns ||= [ 
                              'groups.id', 
                              'groups.insurance_id', 
                              'groups.number', 
                              'groups.quotation', 
                              'groups.tariff_fixed',
                              'groups.full_range',
                              'groups.risk_group',
                              'groups.assurance',
                              'groups.treatment',
                              'groups.ambulatory',
                              'groups.hospital',
                              'groups.infarct',
                              'groups.inability',
                              'groups.death_100_percent',
                              'groups.sum_after_year' 
                            ]
  end

  def searchable_columns
    # list columns inside the Array in string dot notation.
    # Example: 'users.email'
    @searchable_columns ||= [
                              'groups.id', 
                              'groups.insurance_id', 
                              'groups.number', 
                              'groups.quotation', 
                              'groups.tariff_fixed',
                              'groups.full_range',
                              'groups.risk_group',
                              'groups.assurance',
                              'groups.treatment',
                              'groups.ambulatory',
                              'groups.hospital',
                              'groups.infarct',
                              'groups.inability',
                              'groups.death_100_percent',
                              'groups.sum_after_year' 
                            ]
  end

  private

  def data
    # comma separated list of the values for each cell of a table row
    # example: record.attribute,
    records.map do |record|
      [
        record.id, 
        record.insurance_id, 
        record.number, 
        record.quotation_name, 
        record.tariff_fixed_name,
        record.full_range_name,
        record.risk_group,
        record.assurance,
        record.treatment,
        record.ambulatory,
        record.hospital,
        record.infarct,
        record.inability,
        record.death_100_percent? ? 'Tak' : 'Nie',
        record.sum_after_year 
      ]
    end
  end

  def get_raw_records
    # insert query here
    #Group.all
    Group.all.where(insurance_id: options[:only_for_current_insurance_id])
  end

  # ==== Insert 'presenter'-like methods below if necessary
end

Pewnie wiele uwag będzie do tego kodu (chętnie przeczyttam wszystkie) ale bądźcie litościwi dla ucznia “zielonej szkoły” :wink:

dobra…
dodałem: gem ‘thin’ i uruchamiam Thin web server i po sprawie w czasie developerki i jest gites.

Mam nadzieję, że jak przeniosę do produkcji na nginx+passenger też nie będzie problemu, bo wyczytałem gdzieś, że tylko WEBrick ma ustawione takie małe uri

To nie jest rozwiązanie :frowning: nie wiem też do końca przy jakim requeście występuje ten error, jakbyś wkleił kawałek więcej niż tu

[2015-01-21 23:48:45] ERROR WEBrick::HTTPStatus::RequestURITooLarge
[2015-01-21 23:48:45] ERROR TypeError: can't convert nil into an exact number

to byłoby coś łatwiej powiedzieć (podejrzewam, że jest to ten ajax: $('#insurance-groups').data('source') który można by przepisać na nie-1-linera, ale ciężko zgadywać.

[2015-01-22 17:13:19] ERROR WEBrick::HTTPStatus::RequestURITooLarge
[2015-01-22 17:13:19] ERROR TypeError: can’t convert nil into an exact number
/home/bodzio/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/core_ext/time/calculations.rb:226:in -' /home/bodzio/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/core_ext/time/calculations.rb:226:inminus_with_duration’
/home/bodzio/.rvm/gems/ruby-2.2.0/gems/activesupport-4.2.0/lib/active_support/core_ext/time/calculations.rb:237:in minus_with_coercion' /home/bodzio/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/webrick/accesslog.rb:111:insetup_params’
/home/bodzio/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/webrick/httpserver.rb:219:in access_log' /home/bodzio/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/webrick/httpserver.rb:111:inrun’
/home/bodzio/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/webrick/server.rb:294:in `block in start_thread’

nic więcej nie ma.

Ale odkryłem coś bardzo ciekawego.
Można używać WEBrick’a i też nie ma błędów, gdy tylko się doda gem “thin”!!! :open_mouth:

Chcąc wygenerować ten błąd uruchomiłem “Rails s” czyli klasycznego WEBricka i o dziwo, nie pojawił się żaden błąd! Wyczyściłem cały katalog public i tmp i uruchomiłem ponownie. Działa nadal!
…Ale usunąłem gem “thin” z GemFile, wykonałem “gem uninstall thin” i WEBric znowu sypie błędami. :open_mouth: :open_mouth: :open_mouth:

Sprawdziłem to dwukrotnie (ponownie dodając thin - wszystko działa, usuwając - pojawiają się błędy)!

Bazowanie na tym, jaki limit URI obsluguje / nie obsluguje serwer, to nie jest dobra sciezka moim zdaniem. Poniewaz DataTables generuje bardzo dlugie urle dla duzej ilosci kolumn, bezpieczniejsze byloby wysylanie tego albo POST-em z parametrami w ciele wywołania (albo GET-em z parametrami w ciele, jesli sie da) - tak jak to sugeruje @Kalaf

Z dokumentacji DataTables - http://datatables.net/reference/option/ajax

As an object, the ajaxDT object is passed to jQuery.ajax allowing fine control of the Ajax request. DataTables has a number of default parameters which you can override using this option. 
1 Like

Zdaje sie ze ta opcja:

"bServerSide": true

powoduje wysylanie (wszystkich) requestow uzywajac POST zamiast GET.

1 Like

Zaraz to sprawdzę, co jednak nie zmienia faktu, że zachowanie po dodaniu thin’a jest zaskakujące (przynajmniej dla mnie)

Poprzednio, gdy ilość kolumn była niewielka i WEBrick jeszcze się nie wysypywał się, to było coś takiego:

Started GET “/individuals.json?draw=1&columns%5B0%5D%5Bdata%5D=0&columns%5B0%5D%5Bname%5D=&columns%5B0%5D%5Bsearchable%5D=false&columns%5B0%5D%5Borderable%5D=false&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=1&columns%5B1%5D%5Bname%5D=&columns%5B1%5D%5Bsearchable%5D=true&columns%5B1%5D%5Borderable%5D=true&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B1%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B2%5D%5Bdata%5D=2&columns%5B2%5D%5Bname%5D=&columns%5B2%5D%5Bsearchable%5D=true&columns%5B2%5D%5Borderable%5D=true&columns%5B2%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B2%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B3%5D%5Bdata%5D=3&columns%5B3%5D%5Bname%5D=&columns%5B3%5D%5Bsearchable%5D=true&columns%5B3%5D%5Borderable%5D=true&columns%5B3%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B3%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B4%5D%5Bdata%5D=4&columns%5B4%5D%5Bname%5D=&columns%5B4%5D%5Bsearchable%5D=true&columns%5B4%5D%5Borderable%5D=true&columns%5B4%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B4%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B5%5D%5Bdata%5D=5&columns%5B5%5D%5Bname%5D=&columns%5B5%5D%5Bsearchable%5D=true&columns%5B5%5D%5Borderable%5D=true&columns%5B5%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B5%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B6%5D%5Bdata%5D=6&columns%5B6%5D%5Bname%5D=&columns%5B6%5D%5Bsearchable%5D=true&columns%5B6%5D%5Borderable%5D=true&columns%5B6%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B6%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B7%5D%5Bdata%5D=7&columns%5B7%5D%5Bname%5D=&columns%5B7%5D%5Bsearchable%5D=true&columns%5B7%5D%5Borderable%5D=true&columns%5B7%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B7%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B8%5D%5Bdata%5D=8&columns%5B8%5D%5Bname%5D=&columns%5B8%5D%5Bsearchable%5D=true&columns%5B8%5D%5Borderable%5D=true&columns%5B8%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B8%5D%5Bsearch%5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=0&order%5B0%5D%5Bdir%5D=asc&start=0&length=10&search%5Bvalue%5D=&search%5Bregex%5D=false&=1421945891928" for 127.0.0.1 at 2015-01-22 17:58:38 +0100
Processing by IndividualsController#index as JSON
Parameters: {“draw”=>“1”, “columns”=>{“0”=>{“data”=>“0”, “name”=>"", “searchable”=>“false”, “orderable”=>“false”, “search”=>{“value”=>"", “regex”=>“false”}}, “1”=>{“data”=>“1”, “name”=>"", “searchable”=>“true”, “orderable”=>“true”, “search”=>{“value”=>"", “regex”=>“false”}}, “2”=>{“data”=>“2”, “name”=>"", “searchable”=>“true”, “orderable”=>“true”, “search”=>{“value”=>"", “regex”=>“false”}}, “3”=>{“data”=>“3”, “name”=>"", “searchable”=>“true”, “orderable”=>“true”, “search”=>{“value”=>"", “regex”=>“false”}}, “4”=>{“data”=>“4”, “name”=>"", “searchable”=>“true”, “orderable”=>“true”, “search”=>{“value”=>"", “regex”=>“false”}}, “5”=>{“data”=>“5”, “name”=>"", “searchable”=>“true”, “orderable”=>“true”, “search”=>{“value”=>"", “regex”=>“false”}}, “6”=>{“data”=>“6”, “name”=>"", “searchable”=>“true”, “orderable”=>“true”, “search”=>{“value”=>"", “regex”=>“false”}}, “7”=>{“data”=>“7”, “name”=>"", “searchable”=>“true”, “orderable”=>“true”, “search”=>{“value”=>"", “regex”=>“false”}}, “8”=>{“data”=>“8”, “name”=>"", “searchable”=>“true”, “orderable”=>“true”, “search”=>{“value”=>"", “regex”=>“false”}}}, “order”=>{“0”=>{“column”=>“0”, “dir”=>“asc”}}, “start”=>“0”, “length”=>“10”, “search”=>{“value”=>"", “regex”=>“false”}, "
”=>“1421945891928”}

obecnie, po zmianie serverSide: true -> serverSide: false

mamy:

Started GET "/individuals.json?_=1421946322365" for 127.0.0.1 at 2015-01-22 18:05:22 +0100
Processing by IndividualsController#index as JSON
  Parameters: {"_"=>"1421946322365"}

Panowie, jesteście WIELCY!!! … i DZIĘKI! :slight_smile:

P.S.
ale sprwa z tym gem 'thin' nadal mnie zastanawia

OOps… :frowning:

ale chyba jeszcze coś muszę zmienić, gdyż pobiera mi tylko jedną (pierwszą) stronę!

Bo coś jest nie tak :stuck_out_tongue: wątpię żeby parametr “serverSide” odpowiadał za to czy request idzie w body czy w url’u. (zauważ, że dalej leci GET). Spróbuj ustawić "type": "post" w ajaxie (z linka @mark http://datatables.net/reference/option/ajax). Będziesz też musiał podmienić w routes’ach żeby akcja kontrolera matchowała POST a nie GET. Nie wiem tylko czy w ajax’ie wystarczy podmienić GET -> POST żeby request poszedł w body (bo niby czemu nie mógłby być url-encoded), ale może oni to sobie jakoś śmiesznie obsługują ;>

True

To może od początku…

Czy będziemy modyfikowali samo:

ajax: { 
  ...
  type: "POST"
},

czy też może $(’#insurance-groups’).data(‘source’), które jest użyte w:

  ajax: $('#nsurance-groups').data('source'),

idzie w diabły?

dla przypomnienia

Pewnie jakoś tak:

ajax: {
          url: $('#companies').data('source'),
          type: "POST"
        }