Rails × Heroku × Google Drive で無料でファイルアップローダー機能作る！

<h1>Herokuで画像をアップロードすると問題が発生</h1>

<h5 style="color:re;">Herokuでは画像をアップロードしてもスリープモードに入ると、画像が消えてしまう。</h5>

これを解決したい。

そこで調べて分かったことが、外部ストレージサービスを利用して、そこに画像をアップロードする。
という手順と分かりました。


<h1>どうしてもお金をケチりたい。</h1>

外部ストレージサービスとして
Amazon Storageを使ってアップロードするのが普通ですが、
<h5>クレジットカード登録が必要ですし、場合によってはお金がかかってしまいます。</h5>

そこでGoogleDriveにアップロードし、GoogleDriveの共有URLを使って画像表示させる。　これで無料に(15GBまで可能)アップロード機能が作れます。

<h1>GoogleDriveでファイルをアップロードするには</h1>

<h2>Google Cloud プラットフォームでやること</h2>
https://console.cloud.google.com/

にアクセスして、新しいプロジェクトを作成してください。

作成した後、 APIとサービスからOauth同意画面に移動し、ユーザの種類は外部にし、アプリ名などを入力します。公開ステータスは本番環境にしてください。

作成し終えたら、認証情報に移動してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565846/2933dde4-f624-2141-6a14-3467027fdff9.png)


認証情報を作成します。

OAuthクライアントIDを選択してください。

アプリケーションの種類は

ウェブ アプリケーション

承認済みのリダイレクト URIは https://ドメイン or http://ドメイン

などにしてください。

次にAPIを追加します。 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565846/5f2f7cc7-dd90-c512-3777-c410efeb98c6.png)

ライブラリを選択してください。

Google Drive API, Google+ API　を追加してください。

<h2>googleDriveにアクセスできるようにする。</h2>

さぁいよいよプログラミングの開始です。


Railsプロジェクトに移動し、Gemfileを開いてください

```ruby
gem 'google_drive'
```
を追加したら、

bundle installを実行し、

Controllerに

(例)

```ruby
         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を

```rb
credentials.code = params[:code]
```

のようにしてcredentials.codeに代入しています。

```rb
credentials.fetch_access_token!
```

このコードにより、アカウントが認証されAccessTokenなどが返ってきます。

その返ってきたAccessTokenで

```rb
@session = GoogleDrive.login_with_oauth(credentials.access_token)
```

これでRailsでGoogleDriveを扱えます！

しかし、ここでとある問題が

<h5>「こんなのいちいち認証してられない！」</h5>

なので、Refresh tokenというものを取得し自動認証させます。

```
REFRESH TOEKNゲットする--- ・・・・・・"
```
と表示され、Refresh tokenが取得できるはずなのでコピーしてメモしておいてください。

コードを修正します。

```rb
	    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)
```
これを

```rb
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```を渡してあげれば安心ですね！

<b>これで毎回認証しなきゃいけないめんどくさい！</b>問題は解決しました。

<h2>google-drive-rubyの基本</h2>

<h4>ファイル　フォルダー すべて取得</h4>

```rb
@session.files

#ファイル一つ一つ取得↓

@session.files.each do |file|
  p file.title
end
```

<h4>ファイル フォルダー検索</h4>

```rb
#名前で検索
 @session.file_by_title("ファイル名 or フォルダ名")
#IDで検索
 @session.file_by_id("ファイルID")
```
<h4>ファイルアップロード</h4>
```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
```

<h4>ファイルを更新</h4>

```rb

@session.update_file("ファイルID")
```

<h4>ファイルを削除(完全に)</h4>

```rb
@session.drive_service.delete_file("ファイルID", supports_all_drives: true)

```

あとは公式ドキュメントやその他サイトをご覧ください。

--------------------------------------
https://tech.stmn.co.jp/entry/tech/7036

https://github.com/gimite/google-drive-ruby

https://www.rubydoc.info/gems/google_drive

-----------------------------------------


<h2>いよいよアップロードする。</h2>

さぁ基本を知ったうえでアップロード機能をさっそく作成してみましょう。


<h3>1.ファイルをアップロードするためのフォルダを作る</h3>
GoogleDriveを開き、新規→フォルダ

今回はtest-uploadとします。

<h4>作ったフォルダを共有する</h4>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565846/5f6be157-006e-8d5e-fc96-00bc16fa0db4.png)

共有を押し、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565846/bdf5ff30-311d-baaa-a760-924aa365f037.png)

リンクを取得の　リンクを知っている全員に変更を押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565846/48376506-cbe4-f759-22c9-74292e22d91d.png)

するとこのようになるので完了を押してください。

<h3>2.Carrierwaveでファイルをアップロードできるようにする</h3>

ここに関しては割愛させていただきます。

参考にしてください。
https://qiita.com/Inp/items/cc447237e23bf10d159e


<h3>3.Carrierwaveでアップロードして、saveした後にGoogleDriveにアップロードする</h3>

例   Fileをアップロードし、保存しGoogleDriveにもアップロードし、GoogleドライブにアップロードしたファイルのIDをデータベースに保存しておく。

```rb
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
```
これでアップロードが完了！

ですが、やはりなかなかアップロードにお時間がかかりますな..

<h2>アップロードしたファイルを表示</h2>


```index.html.erb
<% @posts.each do |post| %>
 <%= image_tag "https://drive.google.com/uc?id=#{post.google_drive_file_id}" %>
<% end %>
```

これでできるはずです！


<h3>あとがき</h3>

やはり、アップロード時間はAmazon Storageには劣るらしいのでそこは仕方がないですね..

動画でも音楽でも画像でもテキストファイルでもなんでもアップロードできるようになります。(しかし、大きなファイルはアップロードできません。)

僕が一番苦戦したところはアカウント認証させて、GoogleDriveをRailsで操作できるようにするところです..

参考になる記事が少ないのもあり、数時間も格闘しました...

この記事を書くのにもかなりの時間を費やしました。　僕はまだ中学生なのでクレジットカードを持てる年齢でもないのでこの方法で試してみたかったのです。

あまり説明がうまくできなくて申し訳ございません。　ですが、少しは役に立ててもらったらうれしいです。

<h3>参考</h3>

https://github.com/gimite/google-drive-ruby

https://tech.stmn.co.jp/entry/tech/7036

https://qiita.com/cigalecigales/items/470e81c78cf3ef350b0c

https://www.rubydoc.info/github/gimite/google-drive-ruby/