railsで写真アップロード機能を実装

環境

手順

写真アップロード用モデルを作成

$ rails g scaffold Picture date:datetime

DBのマイグレートを実行

$ rake db:migrate

サーバーを起動してブラウザでアクセスしてみる

$ rails s

http://localhost:3000/pictures

登録ページが表示されていればここまではOK

Gemのインストール

では、CarrierWaveのインストールをプロジェクトに導入します。

$ vi Gemfile
...
gem "carrierwave"

gemをインストール

$ bundle install

アップローダーの生成

CarrierWaveのジェネレーターでアップローダーを作成する

$ rails g uploader Image
  create  app/uploaders/image_uploader.rb

作成されたファイルのimage_uploader.rbの中をのぞいてみると、ファイルの保存方法(デフォルトはファイル)、保存パス、ファイルのサイズ、拡張子やファイル名の変換などが変更できることがわかる。

CarrierWaveはActiveRecordやMongoId、DataMapperなどのORMと連携することができる。 今回は、RailsのデフォルトでもあるActiveRecordを使って、アップロードしたファイルの情報を保存してみる。

Modelに画像情報保持用のカラムの追加

まずは、Stringカラムをモデルに追加するために、Pictureモデルにマイグレーションファイルを作成し、マイグレート

$ rails g migration add_image_to_picture image:string
$ rake db:migrate

その後、モデルファイルを開き、アップローダーへのマウントする記述を追加

$ app/models/picture.rb
class Picture < ActiveRecord::Base
  mount_uploader :image, ImageUploader
end

画像の追加/編集/表示/削除処理の追加

写真の新規/編集フォームに画像アップロードの入力フィールドを追加する。 hidden属性でimage_cacheを指定しましたが、これは、画像を指定したけれども、バリデーションエラーなどにより保存が失敗した場合の画面再表示時などに、画像情報をキャッシュしておくための領域となる。

$ cat app/views/pictures/_form.html.erb
<%= form_for(@picture) do |f| %>
  <% if @picture.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@picture.errors.count, "error") %> prohibited this picture from being saved:</h2>

      <ul>
      <% @picture.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :date %><br>
    <%= f.datetime_select :date %>
  </div>

  <!-- 追加個所 -->
  <div class="field">
    <% if @picture.image? %>
      <div class="thumbnail">
      <%= image_tag @picture.image.url %>
    </div>
  <% end %><br>
    <%= f.label :image %><br>
    <%= f.file_field :image %>
    <%= f.hidden_field :image_cache %>
  </div>
  <div class="field">
    <!-- 既存レコード(DBに保存されている)かつ、画像が存在する場合 -->
    <% if @picture.persisted? && @picture.image? %>
      <label>
      <%= f.check_box :remove_image %>
      画像を削除
    </label>
  <% end %>
  </div>
  <!-- 追加個所終了 -->

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

コントローラーにファイルの属性を更新できるようにするために、StrongParametersの箇所を修正

$ app/controllers/pictures_controller.rb

...
# Never trust parameters from the scary internet, only allow the white list through.
def picture_params
  # params.require(:picture).permit(:date)
  params.require(:picture).permit(:date, :image, :image_cache, :remove_image)
end

そして、画像がアップロードされたら、詳細画面で表示するようにします。

$ vi app/views/pictures/show.html.erb
<p id="notice"><%= notice %></p>

<p>
  <strong>Date:</strong>
  <%= @picture.date %>
</p>

<!-- 追加箇所 開始 -->
<p>
<strong>Image:</strong>
<% if @picture.image? %>
  <div class="thumbnail">
  <%= image_tag @picture.image.url %>
</div>
<% end %>
</p>
<!-- 追加箇所 終了 -->

<%= link_to 'Edit', edit_picture_path(@picture) %> |
<%= link_to 'Back', pictures_path %>

end

サーバーを起動してhttp://localhost:3000/picturesにアクセス

新規作成で、写真のアップロードや削除ができる

また、このアップロードされたファイルはpublic/uploads/products配下に保存されている

### CarrierWaveの良く使うメソッド

アップローダーをincludeしたモデル次のようなメソッドを使える


#### モデルの作成

product       = Product.new

#### 画像ファイルの設定

product.image = params[:image]         # paramsから設定
product.image = File.open('somewhere') # Fileオブジェクトを設定

#### 保存

product.save!

#### アップローダーの対するメソッド

product.image.url          # => '/url/to/file.png'
product.image.current_path # => 'path/to/file.png'
prodcut.image.identifier   # => 'file.png'
product.image?   # => imageがあるかを true or false で返す

今回はCarrierWaveの基礎的な内容を記載したが、比較的簡単に画像のCRUDActiveRecordのモデルに追加することができることがわかった。