Edited at

Rails で gem を使わず、フォームで画像を扱う方法

More than 1 year has passed since last update.

Rails勉強し出して、フォームで画像を使いたいんだけど、

CarrierWaveやら、Paperclipやら、gemはまだ使いたくない。

PHPみたいに、シンプルに画像を直接プロジェクトのフォルダーに保存できないだろうか。

できます。


概略


フォーム

<%= form_tag('posts', multipart: true) do %>

<input type="file" name="image">
...
<% end %>


コントローラ

File.binwrite("public/my_images_folder/image_name.jpg", params[:image].read)



画像のパス

<img src="/my_images_folder/image_name.jpg" />


画像のパスでは /public/は不要。form_tag では multipart: true をつけ忘れずに。

画像の保存先のフォルダmy_images_folderは先に作成してあげないとアップロードするときに「そんなフォルダないよ」と怒られます。


サンプルアプリ

簡単なサンプルを作って、実用的な使い方を見ていきましょう。

$ rails new image-form-sample

$ cd image-form-sample


/Gemfile

# 以下の行をコメントアウトする (JSON使わないので)

gem 'jbuilder', '~> 2.5'

$ bundle install

$ rails g scaffold post content:text image_name:string
$ rails db:migrate


/app/controllers/posts_controller.rb

  # POST /posts

def create
@post = Post.new(post_params)
if @post.save

# 以下6行を追記
if params[:post][:image]
File.binwrite("public/post_images/#{@post.id}.jpg", params[:post][:image].read)
@post.update(image_name: "#{@post.id}.jpg" )
else
@post.update(image_name: "default.jpg" )
end

redirect_to @post, notice: 'Post was successfully created.'
else
render :new
end
end

# PATCH/PUT /posts/1
def update
if @post.update(post_params)

# 以下4行を追記
if params[:post][:image]
File.binwrite("public/post_images/#{@post.id}.jpg", params[:post][:image].read)
@post.update(image_name: "#{@post.id}.jpg" )
end

redirect_to @post, notice: 'Post was successfully updated.'
else
render :edit
end
end



/app/views/posts/_form.html.erb

<!-- multipart: true を追記 -->

<%= form_with(model: post, local: true, multipart: true) do |form| %>
...
<!-- image_nameの項目を以下に変更 -->
<div class="field">
<%= form.label :image %>
<%= form.file_field :image %>
</div>


/app/views/posts/show.html.erb

<p>

<!-- image_nameの項目を以下に変更 -->
<strong>Image:</strong>
<img src="/post_images/<%= @post.image_name %>" width="200px" />
</p>

$ cd public

$ mkdir post_images
$ cd ..
$ rails s