猫でもわかるWebプログラミングと副業

本業エンジニアリングマネージャー。副業Webエンジニア。Web開発のヒントや、副業、日常生活のことを書きます。

Railsでrake taskの作成 - rake taskにするべきかRails runnerにするべきか

f:id:yoshiki_utakata:20181121093826j:plain

はじめに

RailsでRake taskを作成したい。Twitchの関連アプリを作成していて、TwitchのスクリーンネームからユーザーIDなどの情報を取得するコマンドを定義したい。

環境

  • ruby 2.5
  • rails 5.2

rake task と rails runner

railsでバッチ処理を実装するにあたり、rake taskとrails runnerの2種類が出てきます。下記Qiita記事では rake taskとrails runnerの違いを考察しています。

qiita.com

まあこれ読んでも正直「わからん」という感じなんですが、個人的には下記のような使い分けかなと思っています。

  • rails db:migraterails assets:precompile のように、アプリの開発やデプロイに必要なスクリプトは rake task
  • APIから値を取ってきてDBにinsertするなど、定期処理やアプリケーション動作中に実行する処理は rails runner

今回は「TwitchのユーザーIDを取ってくる」という処理で、そのユーザーIDはconfigやenvなどに設定することを考えているので、「アプリの開発やデプロイに必要なスクリプト」だと考えて、rake taskで実装することを試みます。ただし、rake taskとrails runnerで微妙にお作法などが異なるので、rake taskで実装するのが面倒だと感じたらrails runnerに切り替えていきます。特に、access key などから tokenを取得してくる処理はアプリケーションですでに実装済みなので、そこを使い回せることが条件です。

rake task の作成

./bin/rails --tasks とするとタスク一覧が出てきます。

$ ./bin/rails --tasks
rails about
...
rails db:create
...

rails twitch:user コマンドを作成しようと思います。 rails g task コマンドを利用します。namespaceがtwitchなので、 rails g task twitch とします。

$ rails g task twitch
Running via Spring preloader in process 76080
      create  lib/tasks/twitch.rake

lib/tasks/twitch.rake というファイルができます。

namespace :twitch do
end

タスクを書く

とりあえずhello world

タスクの内容を書いていきます。 rails twitch:user というタスクを作ろうと思うので、

namespace :twitch do
  task :user => :environment do
    puts "task!"
  end
end

こんな感じで書いていきます。とりあえず task!と出力するだけです。

$ rails twitch:token
task!

とりあえず動きました。

RailsのConfigを取得してみる

ではタスクの中身を書いていかなければいけないのですが、twitchのAPIを叩くのにclient_idだったりtokenだったりが必要になるので、rake task上からconfigが引けるのかどうかを確認してみます。

namespace :twitch do
  task :user => :environment do
    puts TwitchSummary::Application.config.twitch_client_id
  end
end

TwitchSummaryはアプリケーション名です。

$ rails twitch:user
5exxxxxxxxxxxxxxxxxxxxxxxxxx

秘匿文字列なのでマスクしていますが、Configを取ってくることはできました。

login name から user id が取ってこれるように

では、twitchのライブラリを利用してユーザーIDが取ってこれるようにしてみます。

namespace :twitch do
  task :user => :environment do
    twitch_login_name = 'riotgamesjp'
    @twitch = TwitchRepository.new(
      TwitchSummary::Application.config.twitch_client_id,
      TwitchSummary::Application.config.twitch_client_secret,
      TwitchSummary::Application.config.twitch_redirect_uri
    )
    twitch_token = TwitchSummary::Application.config.twitch_token_utakata
    user_id = @twitch.get_user_id_by_login(twitch_token, twitch_login_name)
    puts user_id
  end
end

結果

$ rails twitch:user
104833324

引数を受け取る

んで最後に、twitch_login_name = 'riotgamesjp' この部分を引数で受け取るようにしてみます。

namespace :twitch do
  task :user, ['login_name'] => :environment do |task, args|
    puts 'get user id with "' + args[:login_name] + '"'
    @twitch = TwitchRepository.new(
      TwitchSummary::Application.config.twitch_client_id,
      TwitchSummary::Application.config.twitch_client_secret,
      TwitchSummary::Application.config.twitch_redirect_uri
    )
    twitch_token = TwitchSummary::Application.config.twitch_token_utakata
    user_id = @twitch.get_user_id_by_login(twitch_token, args[:login_name])
    puts user_id
  end
end

この実行コマンドは以下です。

$ rails twitch:user[riotgamesjp] 
zsh: no matches found: twitch:user[riotgamesjp]

?!

めっちゃハマりました。zshを使っていると [ が特殊な文字列として表されるっぽいので、こうしたら正しく動きました。

$ rails "twitch:user[riotgamesjp]"
get user id with "riotgamesjp"
104833324

正しく取ってこれました

まとめ

  • rake taskを書いた
  • configとかライブラリとかも全部使える