Herokuで画像をアップロードすると問題が発生
Herokuでは画像をアップロードしてもスリープモードに入ると、画像が消えてしまう。
これを解決したい。
そこで調べて分かったことが、外部ストレージサービスを利用して、そこに画像をアップロードする。
という手順と分かりました。
どうしてもお金をケチりたい。
外部ストレージサービスとして
Amazon Storageを使ってアップロードするのが普通ですが、
クレジットカード登録が必要ですし、場合によってはお金がかかってしまいます。
そこでGoogleDriveにアップロードし、GoogleDriveの共有URLを使って画像表示させる。 これで無料に(15GBまで可能)アップロード機能が作れます。
GoogleDriveでファイルをアップロードするには
Google Cloud プラットフォームでやること
https://console.cloud.google.com/にアクセスして、新しいプロジェクトを作成してください。
作成した後、 APIとサービスからOauth同意画面に移動し、ユーザの種類は外部にし、アプリ名などを入力します。公開ステータスは本番環境にしてください。
作成し終えたら、認証情報に移動してください。
認証情報を作成します。
OAuthクライアントIDを選択してください。
アプリケーションの種類は
ウェブ アプリケーション
承認済みのリダイレクト URIは https://ドメイン or http://ドメイン
などにしてください。
次にAPIを追加します。
ライブラリを選択してください。
Google Drive API, Google+ API を追加してください。
googleDriveにアクセスできるようにする。
さぁいよいよプログラミングの開始です。
Railsプロジェクトに移動し、Gemfileを開いてください
gem 'google_drive'
を追加したら、
bundle installを実行し、
Controllerに
(例)
class PostsController < ApplicationController
require "google_drive"
def index
credentials = Google::Auth::UserRefreshCredentials.new(
client_id: "ここに先ほどGoogleCloudプラットフォームで取得したClient Idを追加",
client_secret: "ここに先ほどGoogleCloudプラットフォームで取得したClient SecretKEYを追加",
scope: [
"https://www.googleapis.com/auth/drive",
"https://spreadsheets.google.com/feeds/",
],
redirect_uri: "http://localhost:3000")
puts "ここにアクセスしてください---" + credentials.authorization_uri.to_s
credentials.code = params[:code]
credentials.fetch_access_token!
puts "REFRESH TOEKNゲットする---" + credentials.refresh_token.to_s
@session = GoogleDrive.login_with_oauth(credentials.access_token)
end
end
こうすると
ここにアクセスしてください---https:// ...
と出るはずなので
そのURLにアクセスしてください。
するとアカウントを選択と出てきます。
GoogleDriveを使いたいアカウントでログインし、クリックすると
権限の付与が出てくるので、
許可してください。
するとlocalhost:3000に飛ばされてパラメーターにcodeがくっついてきます。
そのcodeを
credentials.code = params[:code]
のようにしてcredentials.codeに代入しています。
credentials.fetch_access_token!
このコードにより、アカウントが認証されAccessTokenなどが返ってきます。
その返ってきたAccessTokenで
@session = GoogleDrive.login_with_oauth(credentials.access_token)
これでRailsでGoogleDriveを扱えます!
しかし、ここでとある問題が
「こんなのいちいち認証してられない!」
なので、Refresh tokenというものを取得し自動認証させます。
REFRESH TOEKNゲットする--- ・・・・・・"
と表示され、Refresh tokenが取得できるはずなのでコピーしてメモしておいてください。
コードを修正します。
credentials = Google::Auth::UserRefreshCredentials.new(
client_id: "ここに先ほどGoogleCloudプラットフォームで取得したClient Idを追加",
client_secret: "ここに先ほどGoogleCloudプラットフォームで取得したClient SecretKEYを追加",
scope: [
"https://www.googleapis.com/auth/drive",
"https://spreadsheets.google.com/feeds/",
],
redirect_uri: "http://localhost:3000",
refresh_token: "先ほどメモしたRefresh Token")
credentials.update!(access_token: credentials.refresh_token)
credentials.fetch_access_token!
@session = GoogleDrive.login_with_oauth(credentials.access_token)
これを
class PostsController < ApplicationController
before_action :get_session
def index
end
private
def get_session
credentials = Google::Auth::UserRefreshCredentials.new(
client_id: "ここに先ほどGoogleCloudプラットフォームで取得したClient Idを追加",
client_secret: "ここに先ほどGoogleCloudプラットフォームで取得したClient SecretKEYを追加",
scope: [
"https://www.googleapis.com/auth/drive",
"https://spreadsheets.google.com/feeds/",
],
redirect_uri: "http://localhost:3000",
refresh_token: "先ほどメモしたRefresh Token")
credentials.update!(access_token: credentials.refresh_token)
credentials.fetch_access_token!
@session = GoogleDrive.login_with_oauth(credentials.access_token)
end
end
とbefore_actionで@session
を渡してあげれば安心ですね!
これで毎回認証しなきゃいけないめんどくさい!問題は解決しました。
google-drive-rubyの基本
ファイル フォルダー すべて取得
@session.files
#ファイル一つ一つ取得↓
@session.files.each do |file|
p file.title
end
ファイル フォルダー検索
#名前で検索
@session.file_by_title("ファイル名 or フォルダ名")
#IDで検索
@session.file_by_id("ファイルID")
ファイルアップロード
```rb @session.upload_from_file("ファイルのパス")#フォルダの中にアップロード↡
folder = @session.file_by_title("フォルダ名")
folder.upload_from_file("ファイルのパス")
<h4>ファイル or フォルダのIDやタイトルを取得</h4>
```rb
#アップロードしたファイルのID タイトル を取得する
file = @session.upload_from_file("ファイルのパス")
p file.id
p file.title
ファイルを更新
@session.update_file("ファイルID")
ファイルを削除(完全に)
@session.drive_service.delete_file("ファイルID", supports_all_drives: true)
あとは公式ドキュメントやその他サイトをご覧ください。
いよいよアップロードする。
さぁ基本を知ったうえでアップロード機能をさっそく作成してみましょう。
1.ファイルをアップロードするためのフォルダを作る
GoogleDriveを開き、新規→フォルダ今回はtest-uploadとします。
作ったフォルダを共有する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565846/5f6be157-006e-8d5e-fc96-00bc16fa0db4.png)リンクを取得の リンクを知っている全員に変更を押してください。
するとこのようになるので完了を押してください。
2.Carrierwaveでファイルをアップロードできるようにする
ここに関しては割愛させていただきます。
参考にしてください。
https://qiita.com/Inp/items/cc447237e23bf10d159e
3.Carrierwaveでアップロードして、saveした後にGoogleDriveにアップロードする
例 Fileをアップロードし、保存しGoogleDriveにもアップロードし、GoogleドライブにアップロードしたファイルのIDをデータベースに保存しておく。
class TweetsController < ApplicationController
before_action :get_session
def create
file = params[:post][:file]
@post = Post.create(file: file)
folder = @session.file_by_title("test-upload") #GoogleDriveのtest-uploadフォルダを探す
file_ext = File.extname(@post.file.file.original_filename) #拡張子を取得
file_find = folder.upload_from_file(@post.file.current_path, "test-upload-#{@post.id}-file#{file_ext}") #ファイルをアップロード!
@post.update(google_drive_file_id: file_find.id) #ファイルIDを保存しておく。
redirect_to root_path
end
private
def get_session
credentials = Google::Auth::UserRefreshCredentials.new(
client_id: ENV["CLIENTID"],
client_secret: ENV["CLIENTSECRET"],
scope: [
"https://www.googleapis.com/auth/drive",
],
redirect_uri: "http://localhost:3000",
refresh_token: ENV["REFRESH_TOKEN"])
credentials.update!(access_token: credentials.refresh_token)
credentials.fetch_access_token!
@session = GoogleDrive.login_with_oauth(credentials.access_token)
end
end
これでアップロードが完了!
ですが、やはりなかなかアップロードにお時間がかかりますな..
アップロードしたファイルを表示
<% @posts.each do |post| %>
<%= image_tag "https://drive.google.com/uc?id=#{post.google_drive_file_id}" %>
<% end %>
これでできるはずです!
あとがき
やはり、アップロード時間はAmazon Storageには劣るらしいのでそこは仕方がないですね..
動画でも音楽でも画像でもテキストファイルでもなんでもアップロードできるようになります。(しかし、大きなファイルはアップロードできません。)
僕が一番苦戦したところはアカウント認証させて、GoogleDriveをRailsで操作できるようにするところです..
参考になる記事が少ないのもあり、数時間も格闘しました...
この記事を書くのにもかなりの時間を費やしました。 僕はまだ中学生なのでクレジットカードを持てる年齢でもないのでこの方法で試してみたかったのです。
あまり説明がうまくできなくて申し訳ございません。 ですが、少しは役に立ててもらったらうれしいです。
参考