Подтвердить что ты не робот

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

4b9b3361

Ответ 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