2015-09-17 34 views
5

Jest to problem, z którym się spotykam regularnie. Pozwolę sobie wyjaśnić to na uproszczonym przykładzie:Szyny: filtrowanie wielosegmentowe z pustą opcją

Powiedz, że chcę pokazać stronę wyszukiwania, na której wyniki można filtrować, wybierając jedną lub wiele kategorii produktów. Z punktu widzenia wygląda to tak:

<%= select_tag("product_categories", options_from_collection_for_select(@product_categories, 'id', 'name'), multiple:true, include_blank:"(all categories)" %> 

Teraz w sterowniku, mam coś takiego:

@filtered_products = Product.all 

... 

if params[:product_categories].present? 
    @filtered_products = @filtered_products.where(category_id: params[:product_categories].map(&:to_i)) 
end 

... 
#etc 

Jednakże, jak to jest możliwe, aby odznaczyć multiselect kiedy kliknął, jest pusta opcja. Ale po ustawieniu tej opcji params[:product_categories] zawiera [""]. Wynikiem tego jest instrukcja if do oceny, a jako "" .to_i == 0, otrzymujemy tylko produkty z kategorią 0 (która zwykle nie występuje, ponieważ ActiveRecord uruchamia identyfikatory od 1 w bazie danych). Nie jest to pożądany wynik, ponieważ w rzeczywistości chcemy uzyskać produkty wszystkie, gdy wybrana jest opcja pusta.

Obsługa tego przypadku jest jeszcze trudniejsza, ponieważ możliwe jest przypadkowe wybranie zarówno pustej opcji, jak i jednej lub wielu innych opcji. Więc ta sprawa również musi być rozpatrzona.

Zmieniłem if-oświadczenie

if params[:product_categories].present? && params[:product_categories].any? && (params[:product_categories].length > 1 || params[:product_categories].first != "") 
    ... 
end 

To działa, ale ten kod jest bardzo brzydka. Zastanawiam się, czy istnieje lepszy, bardziej suchy, podobny do Railsów sposób, aby to zrobić.

Odpowiedz

4

Spróbuj

if params[:product_categories].reject!(&:empty?).any? 

end 
5

Kiedy nie masz kategorię jeden wybrany można dodać hidden_field samo jak product_categories uniknąć [""] o wartości zerowej przed swoimi wybranych opcji.

<%= hidden_field_tag "product_categories" %> 
<%= select_tag("product_categories", options_from_collection_for_select(@product_categories, 'id', 'name'), multiple:true, include_blank:"(all categories)" %> 

Następnie, aby sobie z tym poradzić. Nie trzeba mapować (&: id), ponieważ "" zostanie wygenerowany automatycznie w zapytaniu. To jest właśnie dlatego embedded array always showing in multiple select options. Mam nadzieję, że to oczyści twój kod.

4

Po prostu poprawiając nieco odpowiedź na Florin.

params[:product_categories].reject!(&:empty?).any? if params[:product_categories].length > 1