おぴよの気まぐれ日記

おぴよの気まぐれ日記

岡山やプログラミング、ファッションのこと、子育てや人生、生き方についての備忘録。

【Rails】ファイルをデータベースに保存する方法

ファイルを保存する方法はRailsチュートリアルとかでは、CarrierWaveというgemを使う。 だがちょっとしたアプリとか作りたい時には、DBに保存した方が都合がいい時もあるはず。

gemを使う方法は別の機会でまとめるとして、今日はDBに保存する方法を。

モデルを作る

$ rails g model Image name:string picture:binary
  invoke  active_record
  create    db/migrate/20171215092903_create_images.rb
  create    app/models/image.rb
# migrate
class CreateImages < ActiveRecord::Migration[5.0]
  def change
    create_table :images do |t|
      t.string :name
      t.binary :picture

      t.timestamps
    end
  end
end
$ rails db:migrate
== 20171215092903 CreateImages: migrating =====================================
-- create_table(:images)
   -> 0.3369s
== 20171215092903 CreateImages: migrated (0.3370s) ============================

コントラーラーを作る

$ rails g controller Images
Running via Spring preloader in process 7555
      create  app/controllers/images_controller.rb
      invoke  erb
      create    app/views/images
      invoke  helper
      create    app/helpers/images_helper.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/images.coffee
      invoke    scss
      create      app/assets/stylesheets/images.scss
# images_controller.rb
class ImagesController < ApplicationController
  def new
    @image = Image.new
    @image.name = "hogehoge"
  end

  def create
    @image = Image.new(image_paprams)
    @image.name = params[:image][:picture].original_filename
    @image.picture = params[:image][:picture].read

    if @image.save
      redirect_to root_path
    else
      render 'new'
    end
  end

  private

    def image_paprams
      params.require(:image).permit(:name, :picture)
    end

end

ビューを作る

# new.html.erb
<%= form_for(@image) do |f| %>
  <div class="form-group">
    <%= @image.name %>
    <%= f.file_field :picture %>
    <%= f.submit "画像を投稿する" %>
  </div>
<% end %>

↓htmlに変換されると...

<form class="new_image" id="new_image" enctype="multipart/form-data" action="/images" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="ZgO8WthU8KtI/rspO/oVgHavcwUUVQl1jDwm0DQAsZXwCHYLO02KUqcX+Kt54gKlUlQP4sqDe3NUltVWjtZQDw==">
  <div class="form-group">
    hogehoge
    <input type="file" name="image[picture]" id="image_picture">
    <input type="submit" name="commit" value="画像を投稿する" data-disable-with="画像を投稿する" disabled="">
  </div>
</form>

まとめ

こんな感じでしょうか。 とりあえず言いたいことは、

  • binary型のカラムをモデルに用意します。
  • form_forf.file_fieldを使います。
  • params[:image][:picture].readで画像データが保存できる

form_forがよしなにやってくれるのは分かるのだけど、いまいち理解が浅いので色々動かしてみて勉強しよう。

で、実際に登録された画像データはこんな感じです。

$ rails c
> Image.all
  Image Load (1.6ms)  SELECT "images".* FROM "images"
=> #<ActiveRecord::Relation [#<Image id: 1, name: "17704-koala-bear-pv.jpg", picture: "\xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x01\x00H\x00H\x00\x00\xFF\xDB\x00C\x00\n\a\a\b\a\x06\n\b\b\b\v\n\n\v\x0E\x18\x10\x0E\r\r\x0E\x1D\x15\x16\x11...", created_at: "2017-12-15 09:52:29", updated_at: "2017-12-15 09:52:29">]>