画像のアップロードとDBへの保存
Rails環境が用意できており,db:createも済んでいるものとする.
まず,contentモデルを作る.stored_file_nameはファイル名(string型)で,アップロードしたファイルそのものはバイナリデータ(binary型)としてstored_fileに格納する.
$ bin/rails g model content stored_file_name:string stored_file:binary
続いて,コントローラを作る.
$ bin/rails g controller contents_controller index create show
ルーティング(config/routes.rb)を次のように修正しよう.
Rails.application.routes.draw do
resources :contents, only: [ :index, :create, :show ]
end
コントローラは次のように記述する.
app/controllers/contents_controller.rb を以下のように記述する.とりあえず,indexとshowは空のままとする.
class ContentsController < ApplicationController
def index
end
def create
stored_file = content_params[:stored_file]
content = {}
if stored_file != nil
content[:stored_file] = stored_file.read
content[:stored_file_name] = stored_file.original_filename
@content = Content.create(content)
end
redirect_to contents_path
end
def show
end
private
def content_params
params.require(:content).permit(:stored_file, :stored_file_name)
end
end
ビューを作る.アップロードするファイルを選ぶフォームを用意する.
app/views/contents/index.html.erb を次のように編集する.
<h1>Contents Upload Test</h1>
<%= form_with model: Content.new do |f| %>
<div class='field'>
<%= f.file_field :stored_file %>
</div>
<div class='actions'>
<%= f.submit 'Upload' %>
</div>
<% end %>
画像のDBからの読み出しと表示
次に,格納した画像を表示することを考えよう.まずは,登録した画像のファイル名の一覧を表示させるところから手を付ける.
コントローラは次のように修正する.
app/controllers/contents_controller.rb のindexメソッドを用意する.とりあえずは,登録した画像全てを表示させるようにする.
def index
@contents = Content.all.order('created_at asc')
end
次はビューの変更.app/views/contents/index.html.erb を次のように変更する.登録した画像のファイル名一覧が表示されるようにする.
<h1>Contents Upload Test</h1>
<%= form_with model: Content.new do |f| %>
<div class='field'>
<%= f.file_field :stored_file %>
</div>
<div class='actions'>
<%= f.submit 'Upload' %>
</div>
<% end %>
<h2>Registered Files</h2>
<% if @contents&.length > 0 %>
<ul>
<% @contents.each {|c| %>
<li><%= c.stored_file_name %></li>
<% } %>
</ul>
<% end %>
さて,次はいよいよ show 画面で画像を表示させる手順である.まずは,ビューを書き換えてshow 画面へのリンクを用意する.ビューの後半を次のように書き換える.
<h2>Registered Files</h2>
<% if @contents&.length > 0 %>
<ul>
<% @contents.each {|c| %>
<li><%= link_to c.stored_file_name, content_path(c) %></li>
<% } %>
</ul>
<% end %>
これで,このリンクを叩くと show 画面に遷移するようにできた.
show のコントローラを作成する.といっても次のような単純なものでOK.
def show
@content = Content.find(params[:id])
end
show のビューはシンプルなものとする.
app/views/contents/show.html.erb は次の一行だけのファイルである.
<%= image_tag send_img_content_path(@content), width: '400px' %>
ここで send_img_content_path という謎のメソッドが現れた.これを有効にするために,ルーティングの設定を次のように修正する.
Rails.application.routes.draw do
resources :contents, only: [ :index, :create, :show ] do
member do
get 'send_img'
end
end
end
そして,それを受けて画像データを送るメソッド send_img をコントローラに追記する.
def send_img
tmp = Content.find(params[:id])
if (tmp.stored_file.size > 0)
send_data(tmp.stored_file, :disposition => 'inline')
end
end
先のリンクがクリックされたときの動作は次のようなものとなる.
- 指定されたcontent_idをパラメータとしてcontent#showメソッドが起動,ビューであるshow.html.erbがレンダリングされる
- そのなかに書かれているimage_tagで生成された<img>のsrc="..."に指定されているのはsend_imgのパスになる.したがって,再度,クライアントからサーバへの通信が行われ,content#send_imgが起動する.
- content#send_imgによってDBのなかの画像データがファイル化され,送られる.
めでたし.めでたし.
0 件のコメント:
コメントを投稿