HerokuとRailsで自己リツイートを行うTwitterbot(Windows編)

古い記事です。Herokuの無料枠が終了するため以下の方法で作るとお金が発生するようになります。この記事は残しておきますが、近々GAS等を使って改修しようと思います。

改修できました！今後は下の記事を参考にしてください。

https://qiita.com/resignater/items/a1151cea6a92f1f916e7

---
 ツイッターのbot作りたい。
でも検索かけたら自分のbotで検索欄埋め尽くしたくない。
過去にツイートしたものだったら自己リツイートによって再ツイートする仕様にしたい。
あとツイート内容を追加・削除・訂正出来るように管理したい。
既存のwebサービスではちょっと見当たらなかったから自作するかもっと探すかを考えている。

---
自作できたので以下に示す。
# 方法
## コマンドプロンプトを使いやすい位置に置く
コマンドプロンプトについては[このへん](http://proengineer.internous.co.jp/content/columnfeature/4962)を読んでください。タスクバーにピン止めしたりとか。うちのパソコンのOSはWindows10です。
## Rubyをダウンロード
[こちらの記事](https://qiita.com/jnchito/items/08b5be458134073c60e3)を参照
僕の場合MSYS2というのがなかなかインストールできなくて6か月ほど投げ出した覚えがある。最終的に[ここ](http://repo.msys2.org/distrib/x86_64/)からmsys2-base-x86_64-20181211.tar.xzというファイルを直接ダウンロードした気がするがよく覚えていない。
## Rails on Rubyをダウンロード
[先ほどと同じ記事](https://qiita.com/jnchito/items/08b5be458134073c60e3)を参照
途中、処理がバッティングしているというようなエラーが出たのでcatgets-1.1-2、libcatgets-1.1-2というフォルダとgencat.exeというファイルをデスクトップに移したら最後まで行けた。
## Gitのインストール
[ここ](https://git-scm.com/download/win)からGitをダウンロード
## twitterアカウントを創設
志怪小説bot[@shikai_shosetsu](https://twitter.com/shikai_shosetsu)を創設した。
## Herokuのアカウントを作成
[このページ](https://signup.heroku.com/)からアカウントを作成しよう。
## Herokuのcommand類をインストール
よく覚えてない、[ここ](https://devcenter.heroku.com/articles/heroku-cli)からWindows用のをダウンロードしたんだっけか
Windowsにはbrewとかいう便利なコマンドはないのだ。
# 環境
- Ruby 2.4.3p205 (2017-12-14 revision 61247) [x64-mingw32]
- Ruby On Rails 5.2.1.1
- Git 2.19.2.windows.1
- Heroku 7.18.10 win32-x64 node-v11.1.0

環境の表記の仕方はこれで合っているのだろうか
## Railsアプリを作成
[こちらの記事](https://techacademy.jp/magazine/6401)を参考にしながらrailsアプリを作成していこう。まずはコマンドプロンプトに以下のように記述、エンター

```
$ rails new shikai-shosetsu-bot
```
shikai-shosetsu-botのところはお好きなアプリ名で。元記事では新しくディレクトリ作ってたけど特にこれといってないならわざわざ作らなくてもいいんじゃないかと思う。ディレクトリが入れ子になっちゃって大変だった。
### Gemfileの設定
Ruby on RailsではデフォルトでSQLiteというデータベースを使用しているらしいんだけど、これがHerokuでは使えないらしいので、Heroku上ではPostgreSQLというデータベースを使うように設定するといいらしい。詳しくは[元記事](https://techacademy.jp/magazine/6401)参照。
#### 変更前
```text:Gemfile
gem 'sqlite3'
```
#### 変更後
```text:Gemfile
gem 'sqlite3', group: :development
# Use postgress in production mode
gem 'pg', group: :production
```
ちなみにワードパッドで編集した。vimとかEmacsとか使いこなせるようになりたいんだけどね… \#の行はコメントだから自由に書けばいいんだけど、漢字とか仮名とかうまく読み込まれないから、英語かローマ字で分かるように書こう。ついでにTwitterのgemも追加しちゃおう、さっきのの下とか好きなところに以下の文言を追加。

```text:Gemfile
# Use Twitter api
gem 'twitter'
```

そしてコマンドプロンプトでバンドルインストール！

```
$ cd shikai-shosetsu-bot
$ bundle install
```
### 掲示板を作成
```
$ rails generate scaffold tweet content:text tweet_id:string rt_id:string
$ rails db:migrate
```
### フォームをいじる
[この記事](https://qiita.com/ryoya-s/items/bc8a0e39716bb2844f0b)を参考にして\app\views\tweetsにある_form.html.erbファイルを次のように変更
#### 変更前
```text:_form.html.erb
  <div class="field">
    <%= form.label :content %>
    <%= form.text_area :content %>
  </div>

  <div class="field">
    <%= form.label :tweet_id %>
    <%= form.text_field :tweet_id %>
  </div>

  <div class="field">
    <%= form.label :rt_id %>
    <%= form.text_field :rt_id %>
  </div>
```
#### 変更後
```text:_form.html.erb
  <div class="field">
    <%= form.label :content %>
    <%= form.text_area :content, cols: 40, rows: 5 ,maxlength: 140 %>
  </div>
```

### ルーティング設定
アクセスしたときに掲示板がトップページになるようにする。\configにあるroutes.rbを以下のように書き換える。rbファイルはそのまま開いたのでは編集ができないので「プログラムから開く」で好きなテキストエディタを開こう。

```ruby:routes.rb
Rails.application.routes.draw do
  resources :tweets
  root 'tweets#index'
end
```

ここらで一度動かしてみよう。以下のコマンドを入力

```
$ rails s
```

続いてお好きなブラウザのアドレス欄にlocalhost:3000と入力。エラーが起きなければ大成功、起きたらごめんなさい、コマンドプロンプトに残るログを読めばもしかしたら原因がわかるかも…
## Tweet機能の追加
[こちらの記事](https://qiita.com/ryoya-s/items/bc8a0e39716bb2844f0b)を参考にしていきます。[Ryoya Sekino](@ryoya-s)氏に圧倒的感謝
### Twitterアプリケーション登録
[こちらの記事](https://qiita.com/bakira/items/00743d10ec42993f85eb )を参考にしてConsumer Key、Consumer Secret、Access TokenとAccess Token Secretを入手する。サイトはとりあえずgithubに新しくレポジトリを作ってそれにした。
### controllerを編集
\app\controllersにあるtweets_controller.rbファイルを以下のように編集する。
まずはしょっぱなの部分をこう

```ruby:tweets_controller.rb
require "twitter"

class TweetsController < ApplicationController
  before_action :set_tweet, only: [:show, :edit, :update, :destroy]
  before_action :twitter_client, except: :new
  def twitter_client
    @client = Twitter::REST::Client.new do |config|
      config.consumer_key = ENV['CONSUMER_KEY']
      config.consumer_secret = ENV['CONSUMER_SECRET']
      config.access_token = ENV['ACCESS_TOKEN']
      config.access_token_secret = ENV['ACCESS_TOKEN_SECRET']
    end
  end
  ～
```

次にupdateメソッドにtweet_deleteメソッドを付け加える。tweet_deleteメソッドは後程作ります。destroyメソッドにも同様に付け加えてほしい。現状僕の環境でうまくツイートの削除ができてないから人に教えられない状況なんだけれど

```ruby:tweets_controller.rb
  def update
    tweet_delete
    respond_to do |format|
      if @tweet.update(tweet_params)
        format.html { redirect_to @tweet, notice: 'Tweet was successfully updated.' }
        format.json { render :show, status: :ok, location: @tweet }
      else
        format.html { render :edit }
        format.json { render json: @tweet.errors, status: :unprocessable_entity }
      end
    end
  end
```

次にpostメソッドを追加。3箇所あるscreen_name: "shikai_shosetsu"のshikai_shosetsuの部分はご自身のTwitterアカウントの垢名に変えてね。

```ruby:tweets_controller.rb
  def post
    tweet_options = Tweet.where(tweet_id: nil)
    if tweet_options.size != 0
      tweet = tweet_options.shuffle.first
      status = tweet.content
      @client.update(status)
      tw = @client.user_timeline(screen_name: "shikai_shosetsu", count: 1)
      tweet.tweet_id = tw[0].id.to_s
    else
      tweet = Tweet.where.not(tweet_id: nil).shuffle.first
      if tweet.rt_id.present?
        @client.unretweet(tweet.rt_id.to_i)
        @client.retweet(tweet.tweet_id.to_i)
        tw = @client.user_timeline(screen_name: "shikai_shosetsu", count: 1)
        tweet.rt_id = tw[0].id.to_s
      else
        @client.retweet(tweet.tweet_id.to_i)
        tw = @client.user_timeline(screen_name: "shikai_shosetsu", count: 1)
        tweet.rt_id = tw[0].id.to_s
      end
    end
    tweet.save
    redirect_to :root
  end
```

最後にtweet_deleteメソッドをprivateの下に記述

```ruby:tweets_controller.rb
  private
  ～
    def tweet_delete
      if @tweet.tweet_id.present?
        @client.destroy_status(@tweet.tweet_id.to_i)
        @tweet.tweet_id = nil
        @tweet.rt_id = nil
        @tweet.save
      end
    end
  ～
```

### ルーティング設定
再び\configにあるroutes.rbを書き換えてルーティングの設定をする

```ruby:routes.rb
Rails.application.routes.draw do
  resources :tweets do
    collection do
      get 'post'
    end
  end
  root 'tweets#index'
end
```

ツイート機能の確認のために、新しいツイートを追加するページにでもツイートボタンを設置してみよう。\app\views\tweetsにあるnew.html.erbファイルに次の記述を追加

```text:new.html.erb

<button type="submit" style = "width: 70px; height: 25px;"><%= link_to 'tweet', post_tweets_path %></button>

```

### BASIC認証で簡易的にカギをかける
アプリをHerokuに公開する場合、urlがばれたら勝手に投稿とかされかねないので、[この記事](https://qiita.com/KazuyaHara/items/f0f6c2efd6414f2f88f7)を参考にしながら簡易的な認証をかけよう。\app\controllersにあるapplication_controller.rbファイルを以下のように編集する。

```application_controller.rb
class ApplicationController < ActionController::Base
  http_basic_authenticate_with :name => ENV['BASIC_AUTH_USERNAME'], :password => ENV['BASIC_AUTH_PASSWORD'] if Rails.env == "production"
end
```

名前とパスワードは後で設定します。

## Herokuでアプリケーション作成
再び[この記事](https://techacademy.jp/magazine/6401)を参照しながらHerokuにRailsアプリをデプロイしよう。

### アプリケーション作成
```
$ heroku create shikai-shosetsu-bot
```
    
shikai-shosetsu-botのところには自分のアプリ名を。ちなみにアンダーバーが使えないらしいぜ。
### アプリケーションのデプロイ
```
$ git push heroku master
```

### マイグレーションの実行
```
$heroku run rails db:migrate
```

## 環境変数の設定
最後に環境変数を6つ新たにHerokuに登録する。ツイッタートークンとかパスワードとかファイルに直接書いたら誰かに見られてしまう危険のあるものはHeroku上で環境変数として設定すればいいらしい。Herokuのサイト上で登録する方法と、コマンドプロンプトでやる方法の2つあるけど、僕は前者を選んだ。
まずは[Herokuのサイト](https://dashboard.heroku.com/apps)にアクセスして、自分のアプリを選択、Settingsに移動してReveal Config Varsボタンをクリック。Config Varsの最終行から、次の6つをKEY、VALUEとして設定していく。

| KEY                 |       VALUE |    
|:--------------------|:------------------|
| CONSUMER_KEY        | 先ほど[Twitterアプリケーション登録](#twitterアプリケーション登録)でゲットしたconsumer_key |      
| CONSUMER_SECRET     | 同じく先ほどゲットしたconsumer_secret |      
| ACCESS_TOKEN        |同じくゲットしたaccess_token |  
| ACCESS_TOKEN_SECRET |同じくゲットしたaccess_token_secret|  
| BASIC_AUTH_USERNAME | BASIC認証で使う名前 |         
| BASIC_AUTH_PASSWORD | BASIC認証で使うパスワード。簡易的な認証だからバレても大丈夫なものにしておこう|    

## テスト
さてここらで一度動作確認をしてみよう。
http://(自分のHerokuアプリ名).herokuapp.comにアクセスして、New Tweetをクリック。フォームでbotに使うツイートを入力し、Create Tweetをクリックして保存。最後にTweetボタンを押して無事ツイートされたら成功！

## Google Apps Scriptで自動投稿の設定
Heroku上で自動投稿とかの定期的な処理をするときはheroku Schedulerってアドオンを使うのが一般的らしいんだけど、クレジットカードも持ってないのでGoogle Apps Script(GAS)を使うことにした。GASとは[このようなもの](https://qiita.com/t_imagawa/items/47fc130a419b9be0b447)です。

```javascript:sendGet.gs
function sendGet(){
    /* POSTするためのOPTIONを設定 */
    var options = {
        "method": "get",
        "Authorization" : " Basic " + Utilities.base64Encode(userid + ":" + password),
        "muteHttpExceptions": true
    };
    var html = UrlFetchApp.fetch('http://(自分のHerokuアプリ名).herokuapp.com', options);
    Utilities.sleep(60000);
    var response = UrlFetchApp.fetch('http://(自分のHerokuアプリ名).herokuapp.com/tweets/post', options);
    Logger.log(response.getContentText());
}
```
useridとpasswordのところには認証に使う名前とパスワードを入力してほしい。トリガーで6時間おきにツイートまたはリツイートするよう設定した。
**これにて完成である！**
# 課題
- 記事の削除ができない
- 記事が0個のときの処理を書いていない
- 日本語対応
    - erbファイルとかに日本語が混じってるとうまく動かない。いくつか日本語対応できる記事とかみつけたのでおいおい対応することにする。
- 記事の取得の仕方に改善の余地あり
    - 今のままじゃ記事数が増えたら重くなってしまう
- ~~画面がスマホ向けじゃない~~
    - ~~そもそもまだきちんと設計できていないから当たり前なんだけど~~
- なんか140字以上入力できてしまったみたいでツイッターへの投稿時にエラーになってそれで4日ぐらいツイートが止まった。
    - ツイートできない→他全部ツイート済みだから次回時にまたそのツイートが選ばれる→またツイートできないの負のループ
    - 編集しなおしたらまた無事動き出したけど他にもこんな類のエラーが起きたらまたツイートが止まりそう...
- ほかにももし同じことで困っている人がいた時のためにツイート済みのものはRTで済ますTwitter bot 作成アプリ作りたい
    - Twitter認証難しそう
    - 無料のherokuサーバでは耐えられなさそう
    - 要望がもしあったらその時またいろいろ考えよう
  
# 追記
- 1度他の人にRTされたツイートが再びRTされないというバグが発生した。対処法を検討中。
    - どうやら勘違いだったようだ。
- 画面のスマホ対応ができた。
    - \app\views\layoutsのapplication.html.erbにある<%= csp_meta_tag %>の直下に以下を追記した。
  
```ruby:application.html.erb
<meta name="viewport" content="width=device-width, initial-scale=1">
```
- HTMLにUnicodeを直書きすることで日本語が一部書けるようになった。
    - ↓みたいな感じで。ボタンやリンクに書く言葉を日本語化する方法はまだ分かっていない。

```html
</p>&#x3082;&#x3057;&#x304b;&#x3057;&#x305f;&#x3089;&#x3053;&#x3046;&#x3057;&#x305f;&#x3089;&#x6587;&#x5b57;&#x304c;&#x8aad;&#x3081;&#x308b;&#x3088;&#x3046;&#x306b;&#x306a;&#x3093;&#x3058;&#x3083;&#x306a;&#x3044;&#x306e;&#x3063;&#x3066;&#x3044;&#x3046;&#x50d5;&#x306e;&#x4e88;&#x6e2c;&#x3088;&#x3069;&#x3046;&#x304b;&#x5f53;&#x305f;&#x308c;</p>
```
- Heroku の無料枠が終了すると発表されてしまった……どうしよう…