Rails 3: Найти родителя полиморфной модели в контроллере? - PullRequest
12 голосов
/ 07 сентября 2011

Я пытаюсь найти элегантный (стандартный) способ передачи родительского элемента полиморфной модели в представление. Например:

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

Есть ли лучший способ?

EDIT

Я делаю new действие. Путь принимает форму parent_model/:id/picture/new, а параметры включают идентификатор родителя (employee_id или product_id).

Ответы [ 3 ]

6 голосов
/ 07 сентября 2011

Я не совсем уверен, что именно вы пытаетесь сделать, но если вы пытаетесь найти объект, который «владеет» картинкой, вы должны использовать поле 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: Гнев Поли Для вашего нового метода вы можете просто передать идентификатор своему конструктору, но если вы хотите создать экземпляр родительского объекта, вы можете получить его по 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».

1 голос
/ 12 марта 2012

Я только что столкнулся с этой же проблемой.

Способ, который я "вроде" решил, - это определение метода 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

К сожалению, яне могу придумать лучшего пути.Надеюсь, это вам немного поможет.

0 голосов
/ 12 ноября 2012

Это то, как я сделал это для нескольких вложенных ресурсов, где последний параметр - это полиморфная модель, с которой мы имеем дело: (только немного отличается от вашей)

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

...