Jak prezentować - wskazywać dane?

Witam,

Mam do stworzenia formularz, który kojarzy dwie tabele i tworzy związek many_to many.

Oczywiście jest mnóstwo przykładów z użyciem komponentu collection_select - coś w stylu:

    <%= f.collection_select :element_id, 
            Element.data_by_name, 
            :id, :name, 
            { include_blank: false }, { multiple: false } %>

No OK. To jest proste i nawet fajne, gdy mamy kilka-kilkanaście rekordów w modelu Element, bo jakoś nie bardzo sobie wyobrażam, by do komponentu tego załadować np 100 tys pozycji.

Jakie macie sposoby na budowanie formularzy, w których trzeba wybrać jedną lub kilka pozycji z tabeli, która zawiera ich tysiące?

Możesz użyć np. pluginu select2 i ładować dane AJAXem już po wpisaniu np. kilku liter, podobnie jak w przykładzie:

http://select2.github.io/select2/#ajax

Oczywiście, będziesz musiał stworzyć akcję która będzie odpowiadała JSONem z Twoimi rekordami. To tak w telegraficznym skrócie, pokombinuj.

1 Like

Dzięki, przeczytam uważnie.

Ma ktoś jeszcze jakiś pomysł?

Ja również stosuję select2 z ajaxem + paginacja (w przykładach jako infinite scroll). Sprawdza się świetnie.

Rozwiejcie wątpliwości człowieka z zielonej szkoły, proszę.

Używacie tego dodając:

gem "select2-rails"

do GemFile?

Tak. Korzystam z select2-rails. Instalujesz go zgodnie z instrukcja. Odpowiednie wpisy do application.css i application.js. Następnie musisz w JS na odpowiednim selectcie wykonać metode .select2(). Ja lubie sobie robic wlasne inputki w simple form.

class Select2Input < SimpleForm::Inputs::CollectionSelectInput
  def input
    super
  end

  def input_html_options
    super.merge(
      { data: { behaviour: 'select2' }, class: 'form-control' }
    )
  end
end

W formularzu

= f.input :user, label: "User", placeholder: "User", 
  collection: f.object.users, required: false, as: :select2

Wtedy w JS dodaje cos w ten desen

$('[data-behaviour~=select2]').select2({allowClear: true});

Dla roznych kolekcji analogicznie robie czesto inputki i wtedy w JS ktory podalem powyzej w argumencie do metody .select2() podaje rozne opcje jak np. wspomniany wczesniej ajax (zgodnie z instrukcja na stronie select2).

2 Likes

Jeszcze nie wszystko rozumiem ale WIELKIE dzięki za to info :slight_smile:

Pomyśl też, czy nie da się tej listy ograniczyć parametrem np. z innego selecta. Będziesz miał jedno pole więcej do wypełnienia ale przynajmniej będzie szybciej i sprawniej.

Gdyby ktoś łaskawy spojrzał na to, co czynię i ewentualnie wskazał błędy, byłbym wdzięczny.

/config/route.rb

  resources :individuals do
    get 'select2_index', on: :collection
  end

/models/individual.rb

  scope :finder, lambda { |q| where("last_name like :q or first_name like :q or pesel like :q", q: "%#{q}%") }

  def as_json(options)
    { id: id, last_name: last_name, first_name: first_name, pesel: pesel, fullname: fullname }
  end

/controllers/individuals_controller.rb

  def select2_index
    @individuals = Individual.order(:last_name, :first_name).finder(params[:q])
    @individuals_on_page = @individuals.page(params[:page]).per(params[:page_limit])

    respond_to do |format|
      format.html
      format.json { 
        render json: { 
          individuals:  @individuals_on_page.as_json([]),
          total_count: @individuals.count 
        } 
      }
    end
  end

teraz, gdy wywołam:

http://localhost:3000/individuals/select2_index.json?q=Ma otrzymuję:

{“individuals”:[{“id”:20065,“last_name”:“Anioł- Litwin”,“first_name”:“Marta”,“pesel”:“XX07310XXXX”,“fullname”:“Marta Anioł- Litwin, Płock, XX07310XXXX”},{“id”:20047,“last_name”:“Balawejder”,“first_name”:“Marek”,“pesel”:“XX02011XXXX”,“fullname”:“Marek Balawejder, Łańcut, XX02011XXXX”},{“id”:20068,“last_name”:“Litwin”,“first_name”:“Mateusz”,“pesel”:“XX25070XXX”,“fullname”:“Mateusz Litwin, Płock, XX250704698”},{“id”:20032,“last_name”:“Maćkowiak”,“first_name”:“Łukasz”,“pesel”:“XXXX241XXXX”,“fullname”:“Łukasz Maćkowiak, Płock, XX08241XXXX”},{“id”:20049,“last_name”:“Majewski”,“first_name”:“Krzysztof”,“pesel”:“XX0901XXXX”,“fullname”:“Krzysztof Majewski, Płock, XX09010XXXX”},{“id”:20038,“last_name”:“Maniecki”,“first_name”:“Jan”,“pesel”:null,“fullname”:"Jan Maniecki, Plock, "},{“id”:20041,“last_name”:“Maniecki”,“first_name”:“Krzysztof”,“pesel”:null,“fullname”:"Krzysztof Maniecki, Płock, "},{“id”:20003,“last_name”:“Maniecki”,“first_name”:“Rafał”,“pesel”:“XX04300XXXX”,“fullname”:“Rafał Maniecki, Płock, XX04300XXXX”},{“id”:20035,“last_name”:“Olczak”,“first_name”:“Małgorzata”,“pesel”:“XX06080XXXX”,“fullname”:“Małgorzata Olczak, Płock, XX06080XXXX”},{“id”:20042,“last_name”:“Otocka”,“first_name”:“Magdalena”,“pesel”:null,“fullname”:"Magdalena Otocka, Płock, "},{“id”:20057,“last_name”:“Radoliński”,“first_name”:“Maciej”,“pesel”:“XX0826XXXX”,“fullname”:“Maciej Radoliński, Bądkowo Kościelne, XX08260XXXX”}],“total_count”:11}

a gdy http://localhost:3000/individuals/select2_index.json?page=1&page_limit=10&q=Ma
{“individuals”:[{“id”:20065,“last_name”:“Anioł- Litwin”,“first_name”:“Marta”,“pesel”:“XX07310XXXX”,“fullname”:“Marta Anioł- Litwin, Płock, XX07310XXXX”},{“id”:20047,“last_name”:“Balawejder”,“first_name”:“Marek”,“pesel”:“XX02011XXXX”,“fullname”:“Marek Balawejder, Łańcut, XX02011XXXX”},{“id”:20068,“last_name”:“Litwin”,“first_name”:“Mateusz”,“pesel”:“XX25070XXX”,“fullname”:“Mateusz Litwin, Płock, XX250704698”},{“id”:20032,“last_name”:“Maćkowiak”,“first_name”:“Łukasz”,“pesel”:“XXXX241XXXX”,“fullname”:“Łukasz Maćkowiak, Płock, XX08241XXXX”},{“id”:20049,“last_name”:“Majewski”,“first_name”:“Krzysztof”,“pesel”:“XX0901XXXX”,“fullname”:“Krzysztof Majewski, Płock, XX09010XXXX”},{“id”:20038,“last_name”:“Maniecki”,“first_name”:“Jan”,“pesel”:null,“fullname”:"Jan Maniecki, Plock, "},{“id”:20041,“last_name”:“Maniecki”,“first_name”:“Krzysztof”,“pesel”:null,“fullname”:"Krzysztof Maniecki, Płock, "},{“id”:20003,“last_name”:“Maniecki”,“first_name”:“Rafał”,“pesel”:“XX04300XXXX”,“fullname”:“Rafał Maniecki, Płock, XX04300XXXX”},{“id”:20035,“last_name”:“Olczak”,“first_name”:“Małgorzata”,“pesel”:“XX06080XXXX”,“fullname”:“Małgorzata Olczak, Płock, XX06080XXXX”},{“id”:20042,“last_name”:“Otocka”,“first_name”:“Magdalena”,“pesel”:null,“fullname”:"Magdalena Otocka, Płock, "}],“total_count”:11}

Czyli wydaje się, że samo budowanie JSON’a działa prawidłowo

teraz /assets/javascript/search.js

$(document).ready(function() {
  $('#individual_select').select2({
      placeholder: "Select Individual",
      allowClear: true,
      ajax: {
          url: "/individuals/select2_index.json",
          dataType: 'json',
          data: function(term, page) {
              return {
                  q: term,
                  page_limit: 10,
                  page: page
              };
          },
          results: function(data, page) {
              var more = (page * 10) < data.total_count;
              var individuals = $.map( data.individuals, function(individual, i) {
                  return { id: individual.id, text: individual.fullname };
              });
              return { results: individuals, more: more };
          }
      },
      initSelection: function(element, callback) {
          var id=$(element).val();
          if (id!=="") {
              $.get("/individuals/"+id+".json", function(data) {
                  var individual= data.individual;
                  if(individual)
                      callback({ id: individual.id, text: individual.fullname });
              });
          }
      },
      dropdownCssClass: "bigdrop"
  });

});

Czy do tej pory to się trzyma ładu i składu* ?

  • ( niekoniecznie składu węgla i papy :wink: )

Chciałbym serdecznie podziękować wszystkim, a w szczególności MENTERO http://forum.rubyonrails.pl/users/mentero
który wskazał mi drogę, …by idąc ciemną doliną zła się nie ulęknąć :wink: