Rails 3:如何在控制器中找到多态模型的父模型?

12

我正在尝试找到一种优雅(标准)的方法来将多态模型的父级传递给视图。例如:

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) 可以工作,但它似乎有点"hackish"。

#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形式,参数包括父级id (employee_idproduct_id)。

3个回答

7

我不确定你想做什么,但如果你想找到“拥有”图片的对象,你应该能够使用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

这将为您实例化所有“imagables”。

更新II:Poly的愤怒 对于您的新方法,您可以将id直接传递给构造函数,但如果您想实例化父级,则可以从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”的风格。


@dogenpunk,如果Picture必须与其他模型之一关联,那么Picture.allPicture.includes(:imageable).all有什么区别? - Nav
1
includes(:imageable) 会预加载与 imageable 关联的对象。 - dogenpunk
除非您的用户实际上正在从此操作更新父类,否则我不认为需要实例化父类。您只是添加了一个不必要的数据库调用,因为您已经从请求对象中获取了实例化新@picture所需的数据。 - dogenpunk
现在我们从URL中提取名称而不是传递的参数,基本上是相同的事情。我希望有一个params[:parent_model]字段,因为你毕竟是从父级过来的。顺便说一句,我在链接(employee**s**/:id/)中搞砸了; 修改你的代码为...include p.pluralize}。感谢您的帮助。我想我会在Rails Google组中发布这个问题。 - Nav
抱歉,只是你的评论...我正在显示来自父类的一些数据;因此数据库调用很重要。如果您看到新方法,我将两个对象传递给视图。 - Nav
显示剩余3条评论

1

我也遇到了同样的问题。

我“有点”解决它的方法是在每个具有多态关联的模型中定义一个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

这是我为多个嵌套资源完成的方式,其中最后一个参数是我们正在处理的多态模型:(与您自己略有不同)

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。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接