开发者

How do you get the parent of a polymorphic object before its been saved?

I have a standard polymorphic relationship and I need to know who its parent is before I save it.

Class Pict开发者_运维技巧ure < AR::Base
  belongs_to :attachable, :polymorphic => true
end

Class Person < AR::Base
  has_many :pictures, :as => :attachable
end

Class Vehicle < AR::Base
  has_many :pictures, :as => :attachable
end

I'm uploading pictures via Paperclip and I build a processor that needs to do different things to different pictures (ie. the Person pictures should have Polaroid look & the vehicle pictures should have an overlay). My problem is that before the picture is saved I don't know if it is associated with a Person or a Vehicle.

I tried putting a "marker" in Person & Vehicle so that I could tell them appart, but when I'm in the Paperclip processor the only thing I see is the Picture class. :( My next thought is to climb up the stack to try and get the parent caller but that seems quite smelly to me. How would you do it?


You should be able to get it from the polymorphic association.

Class Picture < AR::Base
  belongs_to :attachable, :polymorphic => true

  before_create :apply_filter

  private

  def apply_filter
    case attachable
    when Person
      #apply Person filter
    when Vehicle
      #apply Vehicle filter
    end
  end
end

Or, you can just ask it the association type so it dosen't have to build and compare the objects, but rather just do string comparison.

Class Picture < AR::Base
  belongs_to :attachable, :polymorphic => true

  before_create :apply_filter

  private

  def apply_filter
    case attachable_type
    when "Person"
      #apply Person filter
    when "Vehicle"
      #apply Vehicle filter
    end
  end
end


I "solved" this problem and wanted to post it here so that it may help someone else. My solution was to create a "parent" method on the Picture class that climbed up the stack and found something that looked like it's parent.

WARNING: This is crappy code and should probably not be used under any circumstance. It worked for me, but I can't guarantee that it wont cause bodily harm sometime down the road.

caller.select {|i| i =~ /controller.rb/}.first.match(/\/.+_controller.rb/).to_s.split("/").last.split("_").first.classify.constantize

What this code does is walk up the caller tree looking for a ancestor named *_controller.rb. If it finds one (and it should) then it parses out the name into a class which should be the parent class of the calling code. whew

BTW: I dropped Paperclip and started using CarrierWave. It does this sort of thing much more easily and I was able to get it working in half the time. Yea CarrierWave!


I created an interpolation to solve it. My paperclip model is Asset and Project is the parent model. There are other models like Articles which are under project model and can have attachments.

Paperclip.interpolates :attachable_project_id do |attachment, style|
  attachable = Asset.find(attachment.instance.id).attachable
  if attachable.is_a?(Project)
    project_id = attachable.id
  else
    project_id = attachable.project.id
  end
  return project_id
end

Paperclip.interpolates :attachable_class do |attachment, style|
  Asset.find(attachment.instance.id).attachable.class
end

And used it in the model like:

  has_attached_file :data,
  :path => "private/files/:attachable_project_id/:attachable_class/:id/:style/:basename.:extension",
  :url => "/projects/:attachable_project_id/:attachable_class/:id/:style",
  :styles => { :small => "150x150>" }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜