【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もラストかも!?

この記事が気に入ったらサポートをしてみませんか?