我已将模型设置为使用多态Image模型。这工作正常,但我想知道是否可以更改每个模型的:样式设置。使用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
我尝试在Proc方法中启动调试器。仅填充与附加文件相关的字段:
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">
这是来自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">
我正在使用paperclip(2.3.5)和Rails 3.0.1。无论我做什么,a.instance对象都是只有与填充的附件相关的字段的图像。有什么想法吗?
在Paperclip论坛上阅读了很多内容后,我认为在保存实例之前无法访问该实例。你只能看到Paperclip的东西,就是这样。
我通过使用前置过滤器从图像控制器中预设图像来解决这个问题 - 没有附件
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
答案 0 :(得分:8)
我
我只是在使用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
在我的控制器的create方法中(例如),我从picture
中取出了params
,然后创建了该对象。 (可能没有必要从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
。这里总结的变化使得整个模型在回形针处理器内可用。 关键是分配您的附件属性 last 。
希望这有助于某人。
答案 1 :(得分:5)
我找到了在创建时拾取样式的解决方法。
关键是要实现before_post_process
和after_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
答案 2 :(得分:3)
: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
注意 - 上面的代码应该有效,但老实说我没有设置来验证它,但看起来Paperclip::Attachment#styles
call
如果它响应它,请参阅http://rdoc.info/github/thoughtbot/paperclip/master/Paperclip/Attachment:styles
更新传递给Proc
的对象不是实例,而是Paperclip::Attachment
,但实例可通过附件instance
访问
答案 3 :(得分:1)
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
端
答案 4 :(得分:1)
我喜欢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方法在处理器中可用。
感谢大家的见解!
答案 5 :(得分:1)
我也遇到了同样的问题,在寻找优雅的解决方案后,我没有找到任何“真正”有用的东西。所以,这是我的简单解决方案,现在似乎没问题; (此时我不确定它是否有任何缺点)
在模特中;
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
答案 6 :(得分:1)
经过几个小时深入研究ActiveRecord
和Paperclip
的源代码,我认为这是一个涉及一些猴子修补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
,它首先会分配attributes
来触发对record.#{instance}=
的调用(即Image#file=
),然后将其转发到#assign
并执行post_processing
挂钩,这最终会调用styles
中提供的Proc
has_attached_file
而不会出现多态imageable
被设定。嗯...
我重写了首先构建记录的方法,然后再分配提供的属性。
此外,它在record#new_record?
支票中占foreign_key_for?
。
这样,一旦正确设置了记录,就会分配attributes
。至少我是这么认为的;)
非常欢迎更清洁的解决方案和建设性意见:)
答案 7 :(得分:0)
在处理模型上的动态行为变化时,我遇到了类似的问题。玩弄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的属性,可以通过在图像初始化上使用此代码将其更改为您要添加的任何模块:
def after_initialize
if self.image_style?
extend Object.const_get(image_style)
else
extend DefaultImageStyle
end
end
我只是想知道这是否适用于paperclip,因为after_initialize方法可能会在回形针之后调用它的魔力。值得尝试一下!
答案 8 :(得分:0)
查看附件的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。
答案 9 :(得分:-2)
在生产/登台服务器中遇到同样的问题...但不在我的本地环境中。我在所有服务器(2.3.2和2.2.6)中使用相同的rails / paperclip版本