我正在将 Carrierwave (0.9.0) 与 Fog (1.18.0)、mini_magick (3.6.0) 和 Rackspace CloudFiles 结合使用。我想要合成图像。
我有两个模型:产品和电子邮件。在产品 uploader 中,我尝试创建一个循环遍历所有电子邮件并将产品图像合成在每个 email.background_image
顶部的流程。我还想控制该图像的名称,即:
"#{email.name}_#{product.product_number}.jpg"
我在下面列出了我的过程和方法。测试结果是上传到名为“email_123.png”的云文件的文件和原始图像。该名称目前不包括电子邮件的名称,并且图像未合成,我只是收到原始回件。我在这里缺少什么明显的东西吗?谢谢!
version :email do
process :email_composite
def email_composite
Email.all.each do |email|
email_image = email.secondary.url
email_name = email.name
merge(email_name, email_image)
end
end
def merge(email_name, email_image)
manipulate! do |img|
@product = Product.find(model.id)
email_image = ::MiniMagick::Image.open(email_image)
img = email_image.composite(img, "jpg") do |c|
c.gravity "Center"
end
# img = yield(img) if block_given?
img = img.name "#{email_name}_#{@product.product_number}.png"
img
end
end
end
已更新
首先,我想感谢您的彻底回答,所付出的努力是显而易见的,值得赞赏。
在尝试实现此解决方案时,我还有一些问题。 在 #compose 方法中你有:
email_image = ::MiniMagick::Image.open(email_image)
这应该是:
email_image = ::MiniMagick::Image.open(email_image_url)
我通过看到下面包含的define_method调用来假设这一点(顺便说一句,这很棒 - 我不知道你可以做到这一点):
define_method(:email_image_url) { email.secondary.url }
在获得未定义的方法“versions_for”后,我切换了#versions_for方法,因为我始终希望所有电子邮件都有辅助版本。
之前的版本
def self.versions_for emails
reset_versions!
email.find_each { |e| version_for_email(e) }
end
更改后的版本
def self.versions_for
reset_versions!
Email.all.find_each { |e| version_for_email(e) }
end
此更改使我摆脱了错误。
所有这一切的最终结果是,一切看起来都正常,我可以毫无错误地上传图像,但现在我没有电子邮件版本的结果图像。我仍然得到其他版本,例如拇指等。知道什么可能导致此问题吗?再次感谢您迄今为止提供的所有帮助。
最佳答案
在同一版本中多次调用 manipulate!
会将其 block 中的更改应用于同一图像;您想要的是创建多个版本,一个版本对应于每个电子邮件
。这很棘手,因为 CarrierWave 确实希望您在代码中拥有一小组静态定义的版本;它实际上构建了一个新的匿名 Uploader
类来处理每个版本。
我们可以欺骗它动态构建版本,但它非常丑陋。另外,我们必须小心,不要保留对陈旧 uploader 类的引用,否则我们将无休止地积累类并最终耗尽内存!
# in ProductUploader:
# CarrierWave stores its version classes in two places:
#
# 1. In a @versions hash, stored within the class; and
# 2. As a constant in your uploader, with a name based on its #object_id.
#
# We have to clean out both of them to be sure old versions get garbage
# collected!
def self.reset_versions!
versions.keys.select { |k| k =~ /^email_/ }.each do |k|
u = versions.delete(k)[:uploader]
remove_const("Uploader#{u.object_id}".gsub('-', '_'))
end
end
def self.version_name_for email
"email_#{email.name}".to_sym
end
# Dynamically generate the +version+ that corresponds to the image composed
# with the image from +email+.
def self.version_for_email email
version(version_name_for(email)) do
process :compose
# Use +define_method+ here so that +email+ in the block refers to the
# argument "email" from the outer scope.
define_method(:email_image_url) { email.secondary.url }
# Use the same trick to override the filename for this version.
define_method(:filename) { "#{email_name}_#{model.product_number}.png" }
# Compose +email_image+ on top of the product image.
def compose
manipulate! do |img|
email_image = ::MiniMagick::Image.open(email_image_url)
# Do the actual composition.
img = email_image.composite(img, "jpg") do |c|
c.gravity "Center"
end
img
end
end
end
end
# Clear out any preexisting versions and generate new ones based on the
# contents of +emails+.
def self.versions_for emails
reset_versions!
email.find_each { |e| version_for_email(e) }
end
# After you call Product.versions_for(emails), you can use this to fetch
# the version for a specific email:
def version_for_email email
versions[self.class.version_name_for(email)]
end
要使用此功能,请务必调用 Product.versions_for(Email.all)
(可能在 before_filter
中),然后,您可以访问特定的版本使用 @p.product.version_for(email)
发送电子邮件:
# in your controller:
def action
# Recreate a +version+ for each email.
# If you don't want to overlay *every* email's image, you can also pass a
# subset here.
ProductUploader.versions_for(Email.all)
# Upload a file and its versions to Cloud Files...
@p = Product.find(params[:id])
@p.product = File.open(Rails.root.join('clouds.jpg'), 'r')
@p.save!
end
在您的 View 中,您可以照常使用 url
或任何其他帮助程序:
# in a view:
<% Email.all.find_each do |email| %>
<%= image_tag @p.product.version_for_email(email).url %>
<% end %>
关于carrierwave - 为什么 Carrierwave 和 MiniMagick 图像无法正确合成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20154836/