2

フォグ (1.18.0)、mini_magick (3.6.0)、および Rackspace CloudFiles で Carrierwave (0.9.0) を使用しています。画像を合成したい。

Products と Emails の 2 つのモデルがあります。製品アップローダで、すべての電子メールをループ処理し、それぞれの上に製品画像を合成するプロセスを作成しようとしています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 メソッドを切り替えました。これは、常にすべてのメールにセカンダリ バージョンが必要であるためです。

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

この変更により、エラーを取り除くことができました。

これらすべての最終結果は、すべてが機能しているかのように表示され、エラーなしで画像をアップロードできますが、電子メール バージョンの結果の画像がありません。私はまだ親指などの他のバージョンを取得しています。これを引き起こす原因は何ですか? これまでに提供してくださったすべてのヘルプに改めて感謝します。

4

1 に答える 1

2

同じバージョン内で複数回呼び出すmanipulate!と、そのブロックの変更が同じイメージに適用されます。あなたが望むのは、それぞれに対応する多くのバージョンを作成することですEmail。これは注意が必要です。なぜなら、CarrierWave はコード内に静的に定義されたバージョンの小さなセットを持つことを本当に望んでいるためです。実際には、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)(おそらく a で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

ビューでは、url通常どおりまたは他のヘルパーを使用できます。

# in a view:

<% Email.all.find_each do |email| %>
  <%= image_tag @p.product.version_for_email(email).url %>
<% end %>
于 2013-11-23T03:48:37.370 に答える