views:

70

answers:

3

Hello,

I have set up my models to use a polymorphic Image model. This is working fine, however I am wondering if it is possible to change the :styles setting for each model. Found some examples using STI (Model < Image) However this is not an option for me, because I am using a has_many relation.

Art

has_many :images, :as => :imageable

Image

belongs_to :imageable, :polymorphic => true
has_attached_file :file, :styles => { :thumb => "150x150>", :normal => "492x600>"}
                         #Change this setting depending on model

UPDATE

I tried starting up a debugger inside the Proc method. Only fields related to the attached file is populated:

run'irb(Image):006:0> a.instance => #<Image id: nil, created_at: nil, updated_at: nil, imageable_id: nil, imageable_type: nil, file_file_name: "IMG_9834.JPG", file_content_type: "image/jpeg", file_file_size: 151326, file_updated_at: "2010-10-30 08:40:23">

This is the object from ImageController#create

ImageController#create
@image => #<Image id: nil, created_at: nil, updated_at: nil, imageable_id: 83, imageable_type: "Art", file_file_name: "IMG_9834.JPG", file_content_type: "image/jpeg", file_file_size: 151326, file_updated_at: "2010-10-30 08:32:49">

I am using paperclip (2.3.5) and Rails 3.0.1. No matter what I do the a.instance object is the image with only the fields related to the attachment populated. Any ideas?

UPDATE2

After reading a lot on the Paperclip forum I don't believe it's possible to access the instance before it has been saved. You can onlye see the Paperclip stuff and that's it.

I got around this problem by presaving the image from the Image controller with a before filter - without the attachment

  before_filter :presave_image, :only => :create

  ...

  private

  def presave_image
    if @image.id.nil? # Save if new record / Arts controller sets @image
      @image = Image.new(:imageable_type => params[:image][:imageable_type], :imageable_id => params[:image][:imageable_id])
      @image.save(:validate => false)
      @image.file = params[:file] # Set to params[:image][:file] if you edit an image.
    end
  end
A: 

I've had a similar question when dealing with dynamic behavioral changes on my models. Playing around with irb, I found out that this works:

module Foo
   attr_accessor :bar
end
class Bar
   extends Foo
end
bar.bar = 'test' # 'test'
bar.bar # 'test'
# also works for instances of Bar!

So i would create an attribute called image_style that could be changed to whatever module you want to add, by using this code on Image initialization:

  def after_initialize
    if self.image_style?
       extend Object.const_get(image_style)
    else
       extend DefaultImageStyle
    end
  end

I just wonder if this works with paperclip since the after_initialize method may be called after paperclip does it's magic.. Worth a try though!

Lucas d. Prim
I forgot to mention: The module would have the has_attached_file directive, along with the styles you want!
Lucas d. Prim
hmmm I don't know how to use that in my case. Looks fancy though :)
atmorell
Actually i've just tried it w/ has_attached_file but it doesn't work =/ sorry..
Lucas d. Prim
+2  A: 

the :styles property takes a Proc as argument, so you can do all kinds of fancy stuff :)

class Image < AR::Base
  has_attached_file :file, :styles => Proc.new { |a| a.instance.file_styles }

  def file_styles; { :thumb => "150x150>", :normal => "492x600>" } end
end

class Didum < Image
  def file_styles; { :thumb => "50x50>", :normal => "492x600>" } end
end

Note - the above code should work, but honestly I have no setup to verify it, but looks like the Paperclip::Attachment#styles does call if it responds to it, see http://rdoc.info/github/thoughtbot/paperclip/master/Paperclip/Attachment:styles

UPDATE the object passed into the Proc is not the instance, but the Paperclip::Attachment, but the instance is accessible through instance on the attachment

PS: And I've seen this in some other places, but can't remember where...

lwe
Same problem as Adam's example. The model will crash with a nil error when the model is a new unsaved record. Works fine with saved record though.
atmorell
do you have an info about where the error happens exactly, i.e. in the Proc or where?
lwe
added `Proc.new { |a| Rails.logger.error(a.instance.inspect); { ... } }` in one of my projects (rails 3.0.0, paperclip 2.3.4) and it correctly returned my instance - so... it really might boil down to the version used or something similar...
lwe
I updated my question with the information..
atmorell
+1  A: 

Looking at the Paperclip source for Attachment it looks like the styles hash can take an object that responds to call so you may be able to do something like:

class Image < ActiveRecord::Base
  belongs_to :imageable, :polymorphic => true
  has_attached_file :file, :styles => lambda {|attachment| attachment.instance.imageable_type.constantize.image_styles }
end

Then in any model that has many images:

class Art < ActiveRecord::Base
  has_many :images, :as => :imageable

  def self.image_styles
    { :thumb => "150x150>", :normal => "492x600>" }
  end
end

Edit: Looks like someone else beat me to it :P.

Adam Tanner
Apparently instance_read is for attributes related to the image itself because it prepends the attachment name. The edits I have made should work.
Adam Tanner
Only works when the image already has been saved.
atmorell