#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.