我有以下路线:
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
我想知道上面的问题是否有标准的解决方案,或者是否有更好的方法可以做到。
答案 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