Rails处理多个路径上可用的操作的方法

时间:2011-03-25 23:20:42

标签: ruby-on-rails ruby ruby-on-rails-3 design-patterns

我有以下路线:

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 个答案:

答案 0 :(得分:6)

你有什么是好的,但如果你想要,你也可以使用两种不同的动作。这种方法应该可以让您以后更轻松地更改视图,并且更安全一些。

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 :(得分:1)

有些插件可以为你加载资源,比如declarative_authorization或cancan,我相信还有其他插件。

我看到的其他解决方案是在控制器中创建一个私有方法来加载对象,并且在该方法中基本上与此处的逻辑相同;它只是将它移出索引动作本身。然后,metod也可以被称为前过滤器。

另一种做你的逻辑的方法是从父对象开始(如果你也需要父对象,那就太好了:

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

答案 2 :(得分:0)

def index
  key = [:user_id, :product_id].find{|k| params[k]}
  @reviews = Review.where(key => params[key]).first
  respond_with @reviews
end