Railsで定期実行したいスクリプトを書く

# Railsで定期実行したいスクリプトを書く
- Ruby on Railsで定期的に実行したいスクリプトなどを書くときのメモです。
- **ハマりやすいところもある** ので、全ての手順を記しておきます。

![download.png](https://qiita-image-store.s3.amazonaws.com/0/62822/f8d74872-f392-90a4-a156-02829894560e.png)



## lib以下にスクリプトを記述
- twitterからタグのついたtweetを取得するスクリプトを取得する例

```lib/sns/tw.rb
module Sns::Tw extend self
  def batch
    @client = config
    tags = Settings.batch.hashtags

    latest_tweet = Sns.where(sns_type_id: 2).order(post_date: :desc).first
    latest_id = latest_tweet.nil? ? nil : latest_tweet.post_id

    tags.each do | tag |
      search(tag, latest_id)
    end
  end

  private

  def search(tag, latest_id)
    # 最初であれば10件だけ取っておく
    tweets = if latest_id.nil? 
               @client.search("##{tag}", locale: 'ja', exclude: 'retweets', result_type: 'recent', since_id: latest_id).collect.take(10)
             else
               @client.search("##{tag}", locale: 'ja', exclude: 'retweets', result_type: 'recent', since_id: latest_id).collect
             end
    tweets.each_with_index do | tweet, idx | 
      p idx
      tweet.media.each do | media |
        tw = Sns.find_or_create_by(sns_type_id: 2, post_id: tweet.id.to_s) do | sns |
          sns.remote_image_url = media.media_url.to_s
          sns.post_url = tweet.url.to_s
          sns.post_date = tweet.created_at
        end
      end
    end
  end

  def config
    Twitter::REST::Client.new do |config|
      config.consumer_key     = ENV['TWITTER_CONSUMER_KEY']
      config.consumer_secret  = ENV['TWITTER_CONSUMER_SECRET']
    end
  end
end

```

## autoload_pathsに追加
- **この設定をしないと地味にハマります！！ご注意を！！！**

```config/application.rb
config.autoload_paths += %W(#{config.root}/lib)

# 特にここ！！Rails5から productionでも呼び出せるように設定しないといけない
config.enable_dependency_loading = true 
```
- [Rails5 のproduction環境で lib/ 以下が読み込まれない問題](https://qiita.com/okamu_/items/1c004172176a348ecdc8)


## taskを作成
- コマンドでgenerateする

```
$ bundle exec rails g task sns
```
- rakeファイルを編集する

```lib/task/sns.rake
namespace :sns do
  desc "twitterのハッシュタグから画像を保存するタスク"
  task twitter: :environment do
    Sns::Tw.batch
  end
end
```

- taskが動くか確認をする

```
# 一覧を表示
$ bundle exec rails -T
```

```
# 試しに実行する
$ bundle exec rails sns:twitter
```

## 定期実行する設定
- cronをいい感じに使えるgem `whenever`　を使います。

```Gemfile
gem 'whenever'
```
```
$ bunde install --path vendor/bundle
```

- 設定ファイルを作成

```
$ bundle exec wheneverize . 
    [add] writing `./config/schedule.rb'
    [done] wheneverized! 
```

- config/schedule.rb に設定を記述します。

```config/schedule.rb

set :output, 'log/crontab.log'
ENV['RAILS_ENV'] ||= 'development'
set :environment, ENV['RAILS_ENV']

every 30.minutes do
   rake "sns:twitter"
 end

```

### cronに反映する際のコマンド
- 設定の確認

```
$ bundle exec whenever 
$ bundle exec crontab -e
```

- cronにデータを反映

```
$ bundle exec whenever --update-crontab 
```

- cronからデータを削除

```
$ bundle exec whenever --clear-crontab
```


### CapistranoでWhenever
- デプロイ時に、本番環境にもcronの値をセットしたい時は、Capistranoの設定ファイルに下記を追記します。

```config/deploy.rb
set :whenever_command, "bundle exec whenever"
require "whenever/capistrano"
```

これで cap deploy を行なえば、デプロイ先のcrontabに値が反映されます。

## まとめ
- lib/task　に直接かきたくない
- lib以下にスクリプトを置かない派の人もいる
- crontabはwheneverに任せると楽チン

## 参考記事
- https://qiita.com/yumiyon/items/388fbb84450f49a6ab0d
- ありがとうございました！