Фильтрация индекса

#ruby-on-rails #ruby-on-rails-4

#ruby-on-rails #ruby-on-rails-4

Вопрос:

У меня есть следующий метод индексации

 def index
    @user = User.find_by_username(params[:user_id])
    @search = @user.collections.where(status: params[:status]).search(params[:q])
    @search.sorts = 'created_at desc' if @search.sorts.empty?  
    @collections = @search.result.paginate(page: params[:page])
end
 

Затем я могу использовать следующие ссылки для отображения разных индексов с помощью этого одного действия

 <%= link_to "Collection", user_collections_path(current_user, :status => "Got") %>

<%= link_to "Wantlist", user_collections_path(current_user, :status => "Want") %>
 

Но я хочу также иметь возможность связывать подобные вещи, используя другие поля для фильтрации индекса

 <%= link_to "Assembled", user_collections_path(current_user, :progress => "Assembled") %>
 

и я не вижу, как это написать. Должен ли я использовать области видимости или у меня должны быть альтернативные методы в моем контроллере? Является ли мой первоначальный фильтр «где» плохим способом сделать это в первую очередь?

Ответ №1:

Лучший способ, который я нашел для этого, — использовать драгоценный камень has_scope.

Установил это. Именованные области в моей модели следующим образом

 scope :assembled, -> { where(progress: 'Assembled') }
scope :got, -> { where(status: 'Got') }
scope :want, -> { where(status: 'Want') }
 

Добавлены поля has_scope в контроллер

 has_scope :got, :type => :boolean
has_scope :want, :type => :boolean
has_scope :assembled, :type => :boolean
 

Затем мой индексный метод выглядит следующим образом

 def index
    @user = User.find_by_username(params[:user_id])
    @search = apply_scopes(@user.collections).search(params[:q])
    @search.sorts = 'created_at desc' if @search.sorts.empty?  
    @collections = @search.result.paginate(page: params[:page])
end
 

Затем я могу ссылаться на индекс с любой комбинацией этих областей следующим образом

 <%= link_to collection, user_collections_path(@user, got: true) %>

<%= link_to assembled, user_collections_path(@user, got: true, assembled: true) %>
 

Никаких маршрутов и никаких дополнительных методов. Очень чистый и расширяемый.

Ответ №2:

Вместо этого используйте драгоценный камень

Это решаемая проблема. Я бы использовал для этого такой драгоценный камень, как ransack, вместо того, чтобы заново изобретать колесо. В нем есть отличные вспомогательные методы для обеспечения любой фильтрации, которая вам понадобится.

Комментарии:

1. Я использую ransack для других вещей в своем приложении и не осознавал, что у него есть такая функциональность. Документация довольно краткая. Я попытаюсь найти, как ransack может это сделать.

2. Я думаю, что для этого я использую драгоценный камень has_scope. Не вижу, чтобы ransack делал именно то, что я хочу сам по себе. Может быть ошибочным.

Ответ №3:

Маршруты

В дополнение к San ответу вам нужно создать routes для обработки любых данных, которые вы хотите отправить на свой index (для фильтрации):

Вы бы сделали что-то вроде этого:

 #config/routes.rb
resources :users, except: :show do
   collection do
      get "(:query)", action: :index #-> domain.com/users/:query
   end
end
 

Это позволит вам создавать ссылки, подобные этой:

 <%= link_to "Link", users_path(current_user, query: "whatever") %>
 

Контроллер

Внутри вашего контроллера все ссылки будут попадать в ваше index действие, поэтому вам просто понадобятся некоторые условия, чтобы убедиться, что вы можете обработать запрос «без поиска»:

 def index
    @user = User.find_by_username(params[:user_id])

    if params[:status].present? amp;amp; params[:q].present?
        @search = @user.collections.where(status: params[:status]).search(params[:q])
        @search.sorts = 'created_at desc' if @search.sorts.empty?  
        @collections = @search.result.paginate(page: params[:page])
    end
end
 

Комментарии:

1. Вопрос, мой метод индекса, описанный выше, находится в моем collections_controller, а не в моем users_controller. Должен ли я тогда писать маршрут для :collections, а не для пользователей, поскольку в вашем коде маршрутов не упоминаются коллекции?

2. Я думаю, что нашел способ сделать это, не добавляя много маршрутов. Драгоценный камень has_scope, похоже, делает именно то, что я хочу, с существующими маршрутами и прекрасно работает с ransack.