2013-02-19 4 views
14

У меня есть вложенный ресурс, который принадлежит ко многим различным моделям. Например:Rails: Получение родительского объекта вложенного ресурса

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

У меня буквально десятки моделей, которые я должен расшириться за счет таким образом, что кажется, неаккуратно. Есть ли лучший (возможно, запеченный) подход, который я не рассматриваю?

ответ

11

на самом деле не решение, но вы можете уйти с

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 

, если вы используете соглашение между именем параметра и вашими моделями

+0

Это спасет меня много времени и много линий. Благодаря! – nullnullnull

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 на маршрутах, если вам нужно.

10

То, как я делаю это, добавляет имя класса родительской модели в качестве параметра по умолчанию в маршруте.

Для примера вопрос, это должно быть что-то вроде:

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]) 
+2

Это отличный, самый чистый ответ IMO – niborg

+0

Это приятное решение, однако при его использовании я столкнулся с проблемами в своих спецификациях контроллера. Я не нашел существующий Rails способ установить значение параметра 'model_name' для всей спецификации контроллера, поэтому мне пришлось бы передавать значение в каждом из моих методов spec. – Matt

Смежные вопросы