3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ruby on RailsAdvent Calendar 2024

Day 10

Rails Tasks の CoC と DRY

Last updated at Posted at 2024-12-09

Ruby on RailsCommand Line は豊富で、開発や運用に必要なタスクが揃っています。
カスタム Rake タスクも便利で、開発や運用に必要なタスクを追加することができます。
カスタム Rake タスクの数が増えると継続的な開発が困難になるので、規約を検討しました。

Rails Tasks CoC

主に検討した規約(CoC)は3つ

  • Rake タスクの ネームスペース で、単一機能ごとに .rake ファイルを分離する。
  • Rake タスクの .rake ファイルには、単一機能ごとのクラスの .call を記述する。
  • Rake タスクの DB の操作は dry run で試行ができ、 trail で結果を確認できる。

Hands-on

Rails new

  • rails new コマンドで Rails に必要なファイルが作成されます。
  • Rails Tasks はデフォルトでも 60 件以上 あります。
    • 昔のRailsは rake --tasks コマンドでしたが、今はrails --tasks も使えます。
$ rails new myapp && cd myapp
$ rails --tasks | wc -l # 61

Rails Generate Authentication

  • rails generate authentication コマンドで current, user, session のモデルやコントローラーなど必要なファイルが作成されます。
  • rails db:migrate コマンドでデータベースに users, sessions のテーブルが作成されます。
$ rails generate authentication
$ rails db:migrate

Custom Rails Tasks

  • データベースの users のテーブルのレコードの作成に Custom Rake(Rails) Tasks を利用します。
  • rails generate task users create コマンドで lib/tasks/users.rake ファイルが作成されます。
    • rails generate task コマンドの第一引数は namespace で、 第二引数は task です。
$ rails generate task users create
  • rails --tasks コマンドを実行すると、bin/rails users:create が追加されています。
lib/tasks/users.rake
namespace :users do
  desc "TODO"
  task create: :environment do
  end
end

Namespace

  • Rake タスクを単一機能ごとに分離するために namespace を利用します。
  • mkdir コマンド と mv コマンドで単一機能の .rake ファイルを配置します。
mkdir lib/tasks/users
mv lib/tasks/users.rake lib/tasks/users/create.rake
  • tasks/users/create の順番になるように tasksnamespace 上位階層に追加します。
  • rails --tasks コマンドを実行すると、bin/rails tasks:users:create が追加されています。
lib/tasks/users/create.rake
namespace :tasks do
  namespace :users do
    desc "create users"
    task create: :environment do
    end
  end
end

Call

  • ユーザーを作成する Users::CreateTask クラスの .call を記述します。
  • ログの出力は Rails.logger を利用します。
  • rails --tasks コマンドを実行すると、bin/rails tasks:users:create[password] が追加されています。
lib/tasks/users/create.rake
# bin/rails tasks:users:create[123]
namespace :tasks do
  namespace :users do
    desc "create users"
    task :create, %i[password] => :environment do |_task, args|
      Rails.logger = Logger.new($stdout)
      Rails.logger.info Users::CreateTask.call(password: args.password)
    end
  end
end

Application Tasks

  • 単一機能ごとのクラスは app/tasks にファイルを配置します。
  • ApplicationTask クラスで call メソッド のみを利用するように private_class_method で制御します。
$ mkdir app/tasks
$ touch app/tasks/application_task.rb
  • attr_accessor で dry_run, trail をインスタンス変数で読み書きできるようにします。
app/tasks/application_task.rb
class ApplicationTask
  private_class_method :new

  def self.call(*params)
    new(*params).send(:call)
  end

  attr_accessor :dry_run, :trail

  def initialize(params)
    @dry_run = ENV['DRY_RUN'].present?
    @trail = { dry_run:, params:, message: {} }
  end
end

Users Create Task

  • ユーザーを作成する Users::CreateTask クラスは app/tasks/users にファイルを配置します。
mkdir app/tasks/users
touch app/tasks/users/create_task.rb
app/tasks/users/create_task.rb
class Users::CreateTask < ApplicationTask
  def initialize(params)
    @password = params[:password]
    super
  end

  def call
    ActiveRecord::Base.transaction do
      user = User.create_with(password: @password).find_or_create_by!(email_address: "dev+#{User.count + 1}@example.com")
      trail[:message][:user] = { email_address: user.email_address }
      raise ActiveRecord::Rollback if dry_run
    end
    trail
  end
end

Users Create Tests

  • テストは testspec にファイルを配置します。
    • test/tasks/users/create_task_test.rb
    • spec/tasks/users/create_task_spec.rb

(今回は割愛します。)

Rails Tasks Run

  • bin/rails tasks:users:create[123] コマンドで、ユーザーが作成されます。
$ bin/rails tasks:users:create[123]

dry run

  • dry run は引数やネームスペースで対応を検討しましたが、環境変数の利用がDRYに記述できるので採用しました。
$ DRY_RUN=true bin/rails tasks:users:create[123]

Rails Authentication

  • rails generate controller Home index コマンドで Signed を確認する Welcome ページに必要なファイルが作成されます。
$ rails generate controller Home index

Views

  • Turbo を利用しているので turbo_method: :delete を設定します。
app/views/home/index.html.erb
<h1>Welcome</h1>

<p>Signed in as: <%= Current.user.email_address %></p>
<%= link_to 'Sign out', session_path, data: { turbo_method: :delete } %>

Routes

  • roothome#index を設定します。
config/routes.rb
Rails.application.routes.draw do
  resource :session
  resources :passwords, param: :token
  root "home#index"
end

Rails Server Run

$ rails server

Sign in

  • Rails Tasks で作成した メールアドレス と パスワード を入力します。

image.png

Signed in

  • メールアドレス と パスワード が一致すると Welcome ページが表示されます。

image.png

まとめ

カスタム Rake タスク も CoC や DRY で 継続的な開発が保てるようにしましょう。
認証ジェネレータは Hands-on をするときに、必要なファイルが作成されるので便利です。

ポート株式会社 サービス開発部 Advent Calendar 2024 の10日目と並走しています。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?