Rails 3: Найти родителя полиморфной модели в контроллере?
Я пытаюсь найти элегантный (стандартный) способ передать родительский элемент полиморфной модели на представление. Например:
class Picture < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
class Employee < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
class Product < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
Следующий способ (find_imageable
) работает, но он кажется "хакерским".
#PictureController (обновлено, чтобы включить полный список)
class PictureController < ApplicationController
#/employees/:id/picture/new
#/products/:id/picture/new
def new
@picture = imageable.pictures.new
respond_with [imageable, @picture]
end
private
def imageable
@imageable ||= find_imageable
end
def find_imageable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
end
Есть ли лучший способ?
ИЗМЕНИТЬ
Я выполняю действие new
. Путь принимает форму parent_model/:id/picture/new
, а params включают родительский идентификатор (employee_id
или product_id
).
Ответы
Ответ 1
Я не уверен точно, что вы пытаетесь сделать, но если вы пытаетесь найти объект, который "владеет" изображением, вы должны использовать поле imageable_type, чтобы получить имя класса. Для этого вам даже не нужен вспомогательный метод, просто
def show
@picture = Picture.find(params[:id])
@parent = @picture.imagable
#=> so on and so forth
end
Обновление
Для действия индекса вы можете сделать
def index
@pictures = Picture.includes(:imagable).all
end
Это создаст для вас все "воображаемые".
Обновление II: гнев Poly
Для вашего нового метода вы можете просто передать идентификатор вашему конструктору, но если вы хотите создать экземпляр родителя, вы можете получить его из URL-адреса, например
def parent
@parent ||= %w(employee product).find {|p| request.path.split('/').include? p }
end
def parent_class
parent.classify.constantize
end
def imageable
@imageable ||= parent_class.find(params["#{parent}_id"])
end
Конечно, вы могли бы определить константу в контроллере, которая содержала возможных родителей, и использовать это, а не перечислять их в методе явно. Использование объекта пути запроса чувствует себя немного более "Rails-y" для меня.
Ответ 2
Я столкнулся с этой проблемой.
То, как я "вроде" решал это, определяет метод find_parent в каждой модели с полиморфными ассоциациями.
class Polymorphic1 < ActiveRecord::Base
belongs_to :parent1, :polymorphic => true
def find_parent
self.parent1
end
end
class Polymorphic2 < ActiveRecord::Base
belongs_to :parent2, :polymorphic => true
def find_parent
self.parent2
end
end
К сожалению, я не могу придумать лучшего способа. Надеюсь, это поможет вам немного.
Ответ 3
Так я сделал это для нескольких вложенных ресурсов, где последний параметр - это полиморфная модель, с которой мы имеем дело: (немного отличается от вашего собственного)
def find_noteable
@possibilities = []
params.each do |name, value|
if name =~ /(.+)_id$/
@possibilities.push $1.classify.constantize.find(value)
end
end
return @possibilities.last
end
Тогда в представлении что-то вроде этого:
<% # Don't think this was needed: @possibilities << picture %>
<%= link_to polymorphic_path(@possibilities.map {|p| p}) do %>
Причиной возврата последнего из этого массива является разрешение поиска дочерних/полиданных, то есть @employee.pictures или @product.pictures