XHack勉強会 第5回『Ruby「ゼロから」画像共有サービスを作る』で学んだこと

今回はAWSのS3というサービスに画像をアップロードし、
その画像をsnatraを使って表示させることを学びました。

その情報をまとめたので、ざっくりと説明します。

このノートでざっくり分かること。

【AWSの利用方法】

■AWSとは
アマゾンウェブサービスの略称であり、
あの有名なAmazonが提供してるサービス。

様々なITツール(サーバーやDB、アプリケーションなど)を
クラウド上で使用することが可能で、その種類も豊富。

今回は画像データをアップロードする為、
「S3」というストレージサービスを利用する。

■AWSアカウント後にやるべきこと
まずアカウントを作成したら、
[ルートアカウント認証情報を使用してサインイン]をクリック。

・ルートアカウントとは
AWSアカウントを作成したら、まずこのルートアカウントがもらえる。
これは全てのサービスを追加・使用する権限をもつアカウント。

パソコンで言うなら「管理者(権限を持ったユーザー)」と言ったり、
「Administrator(アドミニストレーター)」と言ったりする。

パソコンで別のユーザーを作って、そっちには権限を与えなければ
システムに影響を与えるソフトのインストールや設定ができなくなる。

そしてまず検索フォームで「IAM」と調べて、
そこでユーザーを追加する。

これで何をするかと言うと、

組織内でAWSアカウントを共有する場合、そのルートアカウントで
ログインさせてしまうと関係ないサービスを勝手に使われたり、
セキュリティ上好ましくない。

なので権限を設定し、特定のサービスやアクションのみしか
出来ないようにすることが出来る。

今回は「S3」を使うので、アクセス許可の設定では
「既存のポリシーを直接アタッチ」から検索フォームにて「S3」と検索。

リストから「AmazonS3FullAccess」をチェックして、ユーザー作成。

その時に表示されたページは、二度と表示されないので
必ずCSVダウンロードをして保管しておくこと。

これで準備はOK。

■S3の利用開始
先程作成したユーザーのURLにアクセスし、
「アカウント:」って書いてるところの数字は変えずにサインイン。

検索フォームに「S3」と入力し、S3にアクセス。
そして新しくバケットを作成。

・バケットとは
絵の通りバケツのこと。入れ物。
要はディレクトリみたいな感じと思えばOK。

「名前とリージョン項目」
・バケット名:好きなバケット名
・リージョン:「アジアパシフィック(東京)」

「アクセス許可の設定」
・パブリックアクセスを全てブロックのチェックを外す
(今回はsinatraからストレージ内画像データを参照するので)

を設定。
そして作ったバケット内にて試しに画像をアップロードする。

ファイルを追加後、
「アクセス許可を設定する」項目の「パブリックアクセス許可を管理する」を「アクセス権限を付与する」に変更。

アップロードしたファイルを見るには選択して「開く」。

そしてこの「オブジェクトURL」が外部からの接続先なのだが、
先程のアクセス権限を付与してなければこのURLに行っても見れない。

その時は「公開する」って押せばOK。

これで準備は完了。


【S3へ画像をアップロードして、ブラウザで表示する方法】

とりあえずまずファイル送信用の簡易的なフォームを作成を作成する為、
下記を「app.rb」に作成。

get '/test' do
 return %Q{
   <form action=upload method=post accept-charset=utf-8 enctype=multipart/form-data>
     <div>                                      # ファイル送信を行う時は必ずこれ↑を記入
       <input type=file name=file value=  id=file>
     </div>
     <div>
       <input type=submit value="Upload &uarr;">  # [&uarr;] とは上矢印(↑)の書き方
     </div>
   </form>
 }
end
・%Q { }について
%記法の内の1つ。
%Q{  }で囲われた内側の””(ダブルクオート)を省略して書ける。
本当は<input type="file" name="file" value="" id="file">と書く。
(&uarr;については特殊文字なので省略できない。)

そしてブラウザで確認するとこんな感じ。

次にS3と接続を行う為にGemファイルを使うのでインストール。
「Gemfile」に下記を追記してbundle install。

gem 'aws-sdk-s3'   #sdkとは開発ツールのこと

そして「app.rb」に下記を追記。

require 'aws-sdk-s3'

get '/test' do
    省略
end

# 下記を追記
post '/upload' do
  upload_image = params[:file]

  @file = upload_image["tempfile"]  # アップロードするファイル
  @type = upload_image["Content-Type"]
  @key_name = "#{SecureRandom.hex}"  # バケットに置く際のキー名(ランダムな英数字)
	
  @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')
  
  # これでアップロード先のURLを取得できる
  @image_url = @s3.bucket(get_bucket_name).object(@key_name).public_url

  erb :image    # 今回はimage.erbを使用

end

こちらも接続情報はdotenvを使うので、「.env」に下記を追記。

AWS_S3_ACCESS_KEY_ID='hogehoge'
AWS_S3_SECRET_ACCESS_KEY='hugahuga'
AWS_S3_BUCKET_NAME='foo'

そして表示部分の画面を作るが、今回は画像表示専用の画面を作成する。
名前を「image.erb」として下記を記載。

<img src= "<%= image["@image_url"] %>">

これでS3に画像をアップロードする準備ができたので、
ブラウザを起動し、[localhost:4567/test]に接続して

「ファイルを選択」ボタンを選択後、「Upload↑」ボタンでアップロード。
ブラウザに画像が表示されれば完了。


【DBに保存したURLでS3内の画像を表示する方法】

このままだとアップロードしたタイミングでしか見れないし、
他の画像も見るならまたアップロードしないといけない。

なのでアップロード先のURLをDBに保存、
そのURLを参照して画像を表示できるようにする。

・直接画像をDB内に保存しない理由
文字情報に比べると圧倒的にファイルサイズが大きく、動作が遅くなる為。

頻繁にやりとりをするDBでは、顕著にそれが現れるので
画像ファイル本体はDB外部に置き、場所だけDB内に保存して読み取る。

保存する為のDBテーブルを新規作成する為、
「create_image_contents.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 image_contents (
   id serial,
   image_url text,
   PRIMARY KEY (id)
 );")
connect.finish

そして実行して下記のようにテーブルが出来たらOK。

そしてまずDBに取得したURLを保存する為に「app.rb」に下記を追記。

〜省略〜

@s3.bucket(ENV['AWS_S3_BUCKET_NAME'])
  .object(@key_name)
  .put(body: @file, content_type: @type, acl: 'public-read')

# 下記を追記

@image_url = @s3.bucket(ENV['AWS_S3_BUCKET_NAME']).object(@key_name).public_url

Mydatabase.exec("
  INSERT INTO image_contents (image_url)
  VALUES ('#{@image_url}');
")
redirect "/show"
end

get '/show' do
 @data = Mydatabase.exec("select * from image_contents;")
 erb :image
end

そしてDB内の画像を表示する為に「image.erb」を下記に書き直す。

<ul>
<% @data.each do |image| %>
  <li>
    <%= image["id"] %>
    <br>
    <img src= "<%= image["image_url"] %>">
  </li>
<% end %>
</ul>

そして画像をアップロードして下記のように表示されれば完成。


ここまで来ると、もうほぼ完成間近。
これまでの知識を組み立てて作れるのが分かってきた。

基礎の中の基礎習得まであともう少し。

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