【5回目】Railsに挫折中の人が、Ruby/Sinatraから再入門してみた(全7回)
5/11より毎週土曜日、株式会社X-HACK主催の勉強会、
【全7回】Ruby / Vue.js「ゼロから」ウェブサービスを作る【初心者向け | 個別指導あり】
に参加しています。
学んだことをこちらでアウトプットしていきます!
今回は5回目!
画像アップロード機能〜Amazon S3の使い方について
説明します!
文中のコードはそのままコピペで動くはず?なので、
最初は処理が分からなくても、まず作ってみましょう!
動かない、間違っている所などあれば教えていただけると嬉しいです!
画像をアップロードしよう!
【画像をアップロード、表示するまでの流れ】
①画像の保管場所を決める。今回は、「Amazon S3」サービスを使用。
②保管場所に画像を保存(アップロード)するための処理を記述。
③保管された画像のパスをDBに登録。
④DBからパスを取得し、erbファイルに表示。
この流れを意識しながら作成すると良いかもです!
⭐︎準備
まずは前回までの復習!ここは、さらっとできるようになりましょう!
詳しくは、これまでの記事を参照してください!
・プロジェクト作成
【ターミナル】
$ mkdir day5-sinatra
$ cd day5-sinatra
$ bundle init
// ファイルの作成
$ touch app.rb
$ touch .env
$ touch .gitignore
$ touch create_board_contents.rb
$ touch mydatabase.rb
$ mkdir views
$ touch views/index.erb
・Gemfile編集
【day4-sinatra/Gemfile】
source "https://rubygems.org"
gem 'dotenv'
gem 'pg'
gem 'sinatra'
gem 'sinatra-contrib'
・bundle install
$ bundle install
または
$ bundle install --path vendor/bundle //(作者はこっち)
・「.env」で環境変数を設定
// DB情報を記述
DATABASE_HOST='ホスト名'
DATABASE_USER='ユーザー名'
DATABASE_PASSWORD='パスワード'
DATABASE_NAME='データベース名'
DATABASE_PORT='5432'
// 今回は、画像を保存するAmazon S3用の環境変数も記述
AWS_S3_ACCESS_KEY_ID='アクセスID'
AWS_S3_SECRET_ACCESS_KEY='アクセスキー'
AWS_S3_BUCKET_NAME='バケット名'
・「.gitignore」でgit管理無視するファイルを設定
.env
/vendor/bundle
・「mydatabase.rb」でDB接続をモジュール化
require 'nokogiri'
require 'open-uri'
require 'pg'
require 'dotenv/load'
module Mydatabase
def self.exec(sql)
@conn = PG.connect(
host: ENV['DATABASE_HOST'],
user: ENV['DATABASE_USER'],
password: ENV['DATABASE_PASSWORD'],
dbname: ENV['DATABASE_NAME'],
port: ENV['DATABASE_PORT']
)
data = @conn.exec(sql)
@conn.finish
data
end
end
・「create_board_contents.rb」でテーブルを作成し、実行
今回は画像のパスを保存する「image」カラムを追加!
【day5-sinatra/create_board_contets.rb】
require 'pg'
require 'dotenv/load'
connect = PG.connect(
host: ENV['DATABASE_HOST'],
user: ENV['DATABASE_USER'],
password: ENV['DATABASE_PASSWORD'],
dbname: ENV['DATABASE_NAME'],
port: ENV['DATABASE_PORT']
)
@data = connect.exec("CREATE TABLE \"board_contents\" (
\"id\" serial,
\"name\" text,
\"comment\" text,
\"commented_at\" timestamp,
\"image\" text, // 追加
PRIMARY KEY (\"id\")
);")
-------------------------
【ターミナル】
$ ruby day5-sinatra/create_board_contets.rb
・「index.erb」を編集
アップロードできるように処理を追記!
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>XHACK勉強会</title>
</head>
<body>
<% @data.each do |data| %>
<ul>
<li>名前:<%= data["name"] %></li>
<li>コメント:<%= data["comment"] %></li>
<li>日時:<%= data["commented_at"] %></li>
</ul>
<!-- 画像を表示 -->
<img width="500" src="<%= data["image"] %>">
<% end %>
<form action="/comments" method="post" accept-charset="utf-8" enctype="multipart/form-data">
名前:<input type="text" name="name">
<input class="form-control" type="text" placeholder="Default input" name="comment">
<!-- ファイルをアップロードできるように追記 -->
<input type="file" name="file" value="" id="file">
<input class="btn btn-light" type="submit" value="送信する">
</form>
</body>
</html>
こんな画面ができあがります!
⭐︎Amazon S3のバケットを作成しよう!
今回は、AWSアカウント作成〜Amazon S3バケット作成までの説明は割愛します。
下記などを参考にして、やってみてください!
https://qiita.com/katsuyoshi/items/d693e57eadc40465e7e6
■少し補足
・Amazon S3は「堅牢性の高さ」「容量無制限」「安価」のため、とても人気が高いクラウドストレージサービス。
・AWSは必ず、機能を制限したIAMアカウントでログインする。
→「S3だけしか使えないように権限を設定」などができる!
⭐︎アップロード処理を実装しよう!
・Gemfileを修正。S3用のGemをインストール
【day5-sinatra/Gemfile】
gem 'aws-sdk-s3'
---------------------------
【ターミナル】
$ bundle install
・まずHTTPリクエストで送られてきたパラメータを確認
【day5-sinatra/app.rb】
(省略)
post '/comments' do
# パラメータを受け取る
@name = params['name']
@comment = params['comment']
upload_image = params[:file]
# ここで確認!
p upload_image
redirect '/'
end
先程のフォーム画面から、ファイルを選択して送信すると・・・
このようなログが出力されます!
この中の"tempfile"と"Content-type"(ファイル形式)の値を使って、S3にアップロードします!
【ログ】
"Content-type"=>"image/png",
"tempfile"=>#<Tempfile:/var/folders/x4/l8mj44pn3vv5xh_p0jsp2mqh0000gn/T/RackMultipart20190610-9014-1au4vbq.png>
・「app.rb」を編集して、S3にアップロード!
require 'sinatra'
require 'sinatra/reloader'
require 'pg'
require 'dotenv/load'
require 'aws-sdk-s3'
require './mydatabase'
get '/' do
# DBからデータを取得
@data = Mydatabase.exec('select * from board_contents;')
erb :index
end
post '/comments' do
# パラメータ受け取る
@name = params['name']
@comment = params['comment']
upload_image = params[:file]
# パラメータ情報から、アップロード処理をしてくれる
@file = upload_image['tempfile'] # アップロードするファイル
@type = upload_image['Content-Type']
@key_name = SecureRandom.hex.to_s # バケットに置く際のキー名(ハッシュ化処理)
@s3 = Aws::S3::Resource.new(
region: 'ap-northeast-1', # リージョン東京
credentials: Aws::Credentials.new(
ENV['AWS_S3_ACCESS_KEY_ID'], # S3用アクセスキー
ENV['AWS_S3_SECRET_ACCESS_KEY'] # S3用シークレットアクセスキー
)
)
@s3.bucket(ENV['AWS_S3_BUCKET_NAME'])
.object(@key_name)
.put(body: @file, content_type: @type, acl: 'public-read')
# S3バケットに保存したpathを受け取る
@image = @s3.bucket(ENV['AWS_S3_BUCKET_NAME']).object(@key_name).public_url
# 画像のpathをDBに保存
sql = "INSERT INTO board_contents (name, comment, commented_at, image) VALUES
('#{@name}', '#{@comment}', current_timestamp, '#{@image}');"
@data = Mydatabase.exec(sql)
redirect '/'
end
これで処理は完成です!
コメントとともに画像が表示されました!!\(^o^)/
以上です!
画像のアップロードできました!!
今回はとよももさんのスピーチ講義もあり、今回も充実の内容でした!!
PREP法!スピーチ練習しなきゃ!
来週は、最後の講義です!noteもラストかも!?