16

我有一个属于许多不同模型的嵌套资源。例如:

resources :users do
  resources :histories, only: [:show]
end

resources :publications do
  resources :histories, only: [:show]
end

resources :events do
  resources :histories, only: [:show]
end

在 中HistoriesController,我想找到父对象,尽管我很难想出一种干的方法来处理这个问题。目前,我能想到的最好的方法是:

if params[:user_id].present?
  @parent = User.find(params[:user_id])
elsif params[:publication_id].present?
  @parent = Publication.find(params[:publication_id])
elsif . . . .

我实际上有几十个模型我必须以这种方式分支,这似乎很草率。有没有我没有考虑的更好的(也许是成熟的)方法?

4

3 回答 3

16

我这样做的方式是将父模型类名称添加为路由中的默认参数。

对于问题示例,这应该类似于:

resources :users, model_name: 'User' do
  resources :histories, only: [:show]
end

resources :publications, model_name: 'Publication' do
  resources :histories, only: [:show]
end

resources :events, model_name: 'Event' do
  resources :histories, only: [:show]
end

这将在 params 哈希中添加模型名称。

然后在控制器/动作中,您可以获得父模型,例如:

params[:model_name].constantize # Gives you the model Class (eg. User)

和外键如:

params[:model_name].foreign_key # Gives you column name (eg. user_id)

因此,您可以执行以下操作:

parent_class = params[:model_name].constantize
parent_foreing_key = params[:model_name].foreign_key

parent_object = parent_class.find(params[parent_foreing_key])
于 2015-09-03T09:17:29.053 回答
13

不是真正的解决方案,但你可以逃脱

parent_klasses = %w[user publication comment]
if klass = parent_klasses.detect { |pk| params[:"#{pk}_id"].present? }
  @parent = klass.camelize.constantize.find params[:"#{klass}_id"]
end

如果您在参数名称和模型之间使用约定

于 2013-02-19T14:08:46.450 回答
1

作为已接受答案的替代方案,您可以使用如下动态路由:

get ':item_controller/:item_id/histories/:id', to: 'histories#show'

这应该允许您在 histories_controller.rb 中访问类似这样的父类

parent_controller = params[:item_controller]
parent_class = parent_controller.singularize.camelize.constantize
@parent = parent_class.find(params[:item_id])

如果需要,您也可以在路由中添加对 item_controller 的约束。

于 2015-06-18T17:25:04.830 回答