地方でリモートワークからの起業

外資系製薬会社、公務員在職中にスパルタキャンプ参加、リモートワークエンジニアから起業しました

heroku,Rails,Carrierwave,cloudinaryで画像アップロードを実装

スポンサーリンク

Rails,Carrierwave,cloudinaryで画像アップロードを実装方法です。

f:id:ihatov08:20160906130811j:plain

Gemfileの追加

gem 'carrierwave'
gem 'cloudinary'
$ bundle install

uploaderの修正

開発時はpublic以下にファイルを保存して、cloudinaryは使用しないようにする

  if Rails.env.development?
    storage :file
  else
    include Cloudinary::CarrierWave
  end

credential

heroku使用時は下記のようにCLIを使用するか、画面上で追加するだけでOK。

heroku addons:create cloudinary

cloudinaryアドオンを追加するとCLOUDINARY_URL環境変数が追加される。 cloudinary gemはこの環境変数を自動的に読み込むので、コードを変更する必要はない。 cloudinary.ymlを設定する方法が他のブログで紹介されているが、環境変数のほうが簡単かつ、セキュアだ。 環境ごとに切り替えたければ、環境変数を変更すれば良い。

carrierwaveのinitializerの追加

config/initializers/carrierwave.rb

CarrierWave.configure do |config|
 config.cache_storage = :file
end

これがないとcloudinary使用時に

Need to implement #cache! if you want to use Cloudinary::CarrierWave::Storage as a cache storage.

のエラーが発生する。

validationエラー時に、画像が表示されない。

carrierwaveのREADMEのとおり、下記のように実装するとvalidationエラー時に画像が表示されない。

<%= image_tag(listing.image.url) if listing.image? %>

対策

対策1:viewを修正する

cloudinaryはレコードが作成されたタイミングで画像がアップロードされるので、validationエラー時は存在しない画像URL を参照するので、画像が表示されない。

対策は下記のようにcacheされている画像パスを指定した。

      <% if listing.main_image_cache %>
        <%= image_tag "/#{listing.main_image.cache_path}" %>
      <% else %>
        <%= image_tag(listing.main_image.url) if listing.main_image? %>
      <% end %>
      <%= f.file_field :main_image, class: "form-control filter-input" %>

cacheはpublic以下にされるので、cache_pathで画像のパスを参照している。 先頭にスラッシュをつけないとasset pipelineの対象となりエラーになるので注意が必要。

対策2:urlメソッドをオーバーライドする

viewはそのままにurlメソッドを追加することでも対応できる。

cacheがある場合はcacheのパスを返し、それ以外の場合はCloudinary::CarrierWaveのurlメソッドをsuperで返す ref:

github.com

class ImageUploader < CarrierWave::Uploader::Base

  def url(*args)
    if cached?
      "/#{cache_path}"
    else
      super
    end
  end