回形针:样式取决于型号(has_many多态图像)

我已将模型设置为使用多态Image模型。 这工作正常,但我想知道是否可以更改每个模型的:styles设置。 使用STI(Model <Image)找到了一些例子但是这对我来说不是一个选项,因为我使用的是has_many关系。

艺术

has_many :images, :as => :imageable 

图片

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

UPDATE

我尝试在Proc方法中启动调试器。 仅填充与附加文件相关的字段:

 run'irb(Image):006:0> a.instance => # 

这是ImageController #create的对象

 ImageController#create @image => # 

我正在使用paperclip(2.3.5)和Rails 3.0.1。 无论我做什么,a.instance对象都是只填充了与附件相关的字段的图像。 有任何想法吗?

UPDATE2

在Paperclip论坛上阅读了很多内容后,我认为在保存实例之前无法访问该实例。 你只能看到Paperclip的东西,就是这样。

我通过使用前置filter从图像控制器预设图像来解决这个问题 – 没有附件

  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 

我在这里参加派对的时间非常晚,但我想澄清一些关于访问此线程中发生的任何其他人的模型数据的事情。 我刚刚使用Paperclip根据模型中的数据应用水印时遇到了这个问题,经过大量调查后才开始工作。

你说:

在Paperclip论坛上阅读了很多内容后,我认为在保存实例之前无法访问该实例。 你只能看到Paperclip的东西,就是这样。

实际上, 如果在分配附件之前已在对象中设置了模型数据, 可以看到模型数据!

分配模型中的附件时,您的回形针处理器和诸如此类的东西会被调用。 如果您依赖于质量分配(或实际上不是),只要为附件分配了值,回形针就可以完成它的工作。

这是我解决问题的方法:

在我的带有附件的模型中(照片),我创建了除附件attr_accessible所有属性,从而在批量分配期间保持附件的分配。

 class Photo < ActiveRecord::Base attr_accessible :attribution, :latitude, :longitude, :activity_id, :seq_no, :approved, :caption has_attached_file :picture, ... ... end 

在我的控制器的创建方法(例如)中,我从params拉出picture ,然后创建了对象。 (可能没有必要从params 删除图片,因为attr_accessible语句应该防止picture被分配,但它不会受到伤害)。 然后设置了照片对象的所有其他属性之后 ,我分配了picture属性。

 def create picture = params[:photo].delete(:picture) @photo = Photo.new(params[:photo]) @photo.picture = picture @photo.save ... end 

在我的例子中,用于应用水印的图片调用的样式之一,即水印attribution保存的文本字符串。 在我更改代码之前,从未应用过属性字符串,并且在水印代码中, attachment.instance.attribution始终为nil 。 这里总结的变化使得整个模型在回形针处理器内可用。 关键是最后分配您的附件属性。

希望这有助于某人。

我找到了在创建时拾取样式的解决方法。 关键是实现before_post_processafter_save挂钩。

 class Image < ActiveRecord::Base DEFAULT_STYLES = { medium: "300x300>", thumb: "100x100>" } has_attached_file :file, styles: ->(file){ file.instance.styles } validates_attachment_content_type :file, :content_type => /\Aimage\/.*\Z/ # Workaround to pickup styles from imageable model # paperclip starts processing before all attributes are in the model # so we start processing after saving before_post_process ->{ !@file_reprocessed.nil? } after_save ->{ if !@file_reprocessed && (file_updated_at_changed? || imageable_type_changed?) @file_reprocessed = true file.reprocess! end } belongs_to :imageable, polymorphic: true def styles if imageable_class.respond_to?(:image_styles) imageable_class.image_styles end || DEFAULT_STYLES end def imageable_class imageable_type.constantize if imageable_type.present? end end 

所以你必须在imageable_class中定义image_styles类方法在我的情况下它是

 class Property < ActiveRecord::Base def self.image_styles { large: "570x380#", thumb: "50x70#", medium: "300x200#" } end end 

:styles属性以Proc为参数,所以你可以做各种奇特的东西:)

 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 

注意 – 上面的代码应该可以工作,但老实说我没有设置来validation它,但看起来像Paperclip::Attachment#styles如果响应它就会call它,请参阅http://rdoc.info/github/thoughtbot/paperclip /主/回形针/附件:风格

UPDATE传递给Proc的对象不是实例,而是Paperclip::Attachment ,但是实例可以通过附件上的实例访问

PS:我在其他一些地方见过这个,但不记得在哪里……

 class Banner < ActiveRecord::Base belongs_to :banner_categoria validates :banner_categoria_id ,{:presence =>{:message => "não informada"}} has_attached_file :arquivo after_initialize :init_attachment def init_attachment self.class.has_attached_file :arquivo, :url => "/system/:class/:attachment/:id/:style/:basename.:extension", :path => ":rails_root/public/system/:class/:attachment/:id/:style/:basename.:extension", :styles => hash = { :banner => { :geometry => "#{self.banner_categoria.largura}x#{self.banner_categoria.altura}>", :quality => 80 }, :thumb => "100x100#" } end 

结束

我喜欢MarkGranoff的答案,但我提出了一个更简单的实现,它为我提供了技巧,似乎更易于维护。

 #create new and instantiate the fields you need ( or all except the attachment ) @photo = Photo.new(:attribution => params[:photo][:attribution], :latitude => params[:photo][:latitude ]) #then just assign all params as normal @photo = Photo.assign_attributes(params[:node]) 

第二个语句分配附件,因此处理器被触发,并且由于您已经分配了:attribution和:latitude,它们的值将通过attachment.instance方法在处理器中可用。

在此感谢大家的见解!

我也遇到了同样的问题,在寻找优雅的解决方案后,我没有发现任何“真正”有用的东西。 所以,这是我现在似乎没问题的简单解决方案; (因此我不确定它目前是否有任何缺点)

在模型中;

 class Asset < ActiveRecord::Base belongs_to :assetable, polymorphic: true has_attached_file :attachment, path: ":rails_root/#{path}/assets/images/:style/:filename", url: '/assets/images/:style/:filename', styles: -> (a) { a.instance.send(:styles) } private def styles raise 'Undefined assetable.' unless assetable if assetable.class == Photo { small: 'x40', medium: '120x', large: '300x' } elsif assetable.class == Avatar { small: 'x40', medium: '120x', large: '300x' } else raise "Styles for #{assetable.class} is not defined." end end end 

在控制器;

 @photo = Photo.new @photo.build_image(assetable: @photo, attachment: params[:photo][:image_attributes][:attachment]) @photo.save 

经过几个小时的挖掘ActiveRecordPaperclip源代码,我认为有一个解决方案涉及一些猴子修补hackery。

我没有彻底测试它,但似乎适合我的谦卑需求。

以下是我的config/initializers/activerecord_associations_patch.rb

 module ActiveRecord module Associations class HasManyAssociation def build_record(attributes) if options[:as] && owner # Unicorns reflection.build_association({}) do |record| set_owner_attributes(record) unless foreign_key_for?(record) record.public_send "#{options[:as]}=", owner end initialize_attributes(record) record.assign_attributes(attributes) end else # Classic Rails way reflection.build_association(attributes) do |record| initialize_attributes(record) end end end end end end 

由于reflection不知道我们的@owner ,它首先分配触发调用record.#{instance}=attributes record.#{instance}= (即Image#file= ),然后将其转发到#assign并执行post_processing hook,其中end导致调用styles Prochas_attached_file提供,而不设置多态imageable 。 呵呵…

我重写了首先构建记录的方法,然后再分配提供的属性。 此外,它占了record#new_record?foreign_key_for? 校验。

这样,一旦正确设置了记录,就会分配attributes 。 至少我是这么认为的;)

最受欢迎的解决方案和建设性意见:)

在处理模型的动态行为变化时,我遇到了类似的问题。 玩弄irb,我发现这有效:

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

因此,我将创建一个名为image_style的属性,通过在Image初始化上使用此代码,可以将其更改为要添加的任何模块:

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

我只是想知道这是否适用于paperclip,因为after_initialize方法可能会在回形针之后调用它的魔法。值得一试!

查看附件的Paperclip源,看起来styles哈希可以采用响应call的对象,这样您就可以执行以下操作:

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

然后在任何有许多图像的模型中:

 class Art < ActiveRecord::Base has_many :images, :as => :imageable def self.image_styles { :thumb => "150x150>", :normal => "492x600>" } end end 

编辑 :看起来像别人打败了我:P。

在生产/登台服务器中遇到同样的问题…但不在我的本地环境中。 我在所有服务器中使用相同的rails / paperclip版本(2.3.2和2.2.6)