Rails Способ обработки действий, доступных на нескольких маршрутах. - PullRequest
5 голосов
/ 26 марта 2011

У меня есть следующие маршруты:

resources :users do
  # List reviews made by user
  resources :reviews, :only => [ :index ]
end

resources :products do
  # List reviews by product, and provide :product_id for creation
  resources :reviews, :only => [ :index, :new, :create ]
end

# Other actions don't depend on other resources
resources :reviews, :except => [ :index, :new, :create ]

Все выглядит правильно, кроме ReviewsController#index:

def index
  if params[:user_id]
    @reviews = Review.find_all_by_user_id params[:user_id]
  else
    @reviews = Review.find_all_by_product_id params[:product_id]
  end
  respond_with @reviews
end

Мне было интересно, есть ли стандартное решение проблемы, описанной выше, или есть лучший способ сделать это.

Ответы [ 3 ]

6 голосов
/ 26 марта 2011

То, что у вас есть, прекрасно, но если вы хотите, вы можете использовать два разных действия. Этот подход должен позволить вам легче изменить представление позже, и он немного безопаснее.

match '/products/:product_id/reviews' => 'reviews#product_index'
match '/users/:user_id/reviews' => 'reviews#user_index'

Это также сделает код вашего контроллера немного чище и менее восприимчивым к нечетным запросам, таким как /products/10/reviews?user_id=100, что приведет к тому, что вместо отзывов о продукте будут отображаться отзывы пользователей.

def product_index
  @reviews = Review.find_all_by_product_id params[:product_id]
  respond_with @reviews
end

def user_index
  @reviews = Review.find_all_by_user_id params[:user_id]
  respond_with @reviews
end

Другой альтернативой также является использование других контроллеров:

match '/products/:product_id/reviews' => 'product_reviews#index'
match '/users/:user_id/reviews' => 'user_reviews#index'
1 голос
/ 26 марта 2011

Некоторые плагины имеют способы загрузки ресурсов для вас, такие как декларативное_авторизация или канкан, я уверен, что есть и другие.

Другие решения, которые я видел, состоят в том, чтобы создать приватный метод в контроллере для загрузки объекта, и в этом методе по сути та же логика, что и у вас;он просто перемещает его из самого действия index.Затем метод также может быть вызван как фильтр before.

Еще один способ сделать вашу логику - это начать с родительского объекта (хорошо, если вам также нужен родительский объект:

before_filter :load_collection, :only => :index

private
def load_collection
  if params[:user_id]
    @user = @parent = User.find(params[:user_id])
  else
    @product = @parent = Product.find(params[:product_id])
  end
  @reviews = @parent.reviews
end
0 голосов
/ 26 марта 2011
def index
  key = [:user_id, :product_id].find{|k| params[k]}
  @reviews = Review.where(key => params[key]).first
  respond_with @reviews
end
...