💭

alba用の"rails g alba hoge"みたいなジェネレータを作った

2024/10/26に公開

はじめに

みなさん、こんにちは torihaziです

今日は昨日初めて知ったRailsの自作ジェネレータを実際に使ってみたということで練習がてら作ってみました

昨日の時点で便利では?と思ったので今後も使っていきたいと思います

ちなみにalbaはこれです。Railsのシリアライザ?です。

https://github.com/okuramasafumi/alba

経緯

今作っているXクローン用に昨日ずっとRailsのSerializerを探していて、jsonapi-serializerとか色々触ってみたのですがどれも「うーん」ということで辿り着いたのが albaでした。

その時の体験記がこれです。

https://torihazi.hateblo.jp/entry/2024/10/25/220337

このついでに毎回ファイル手動で作るのだるいとなってrails g serializerがあることを知り、さらにこの"ジェネレータ"自体が自分でも作れるのを知りました。

で、albaが見てみた感じなさそうだったのでその時得た知識をもとに作ってみよう!となって今に至ります。

その前に

導入方法とかはこの方のものを参考にしてください

https://zenn.dev/hujuu/articles/implement-alba-in-rails

どういうものか

結論言うと、

rails g alba tweetWithImages --model tweet

とするとapp/resources配下にファイルが出来ます。
なければ作成されます

tweets_with_images_resource.rb
# frozen_string_literal: true

class TweetsWithImagesResource < BaseResouce
  root_key :tweet

  attributes :id
end
base_resource.rb
class BaseResource
  include Alba::Resource
end

ちなみにnamespace作って云々したければ

rails g alba hoge/hoge --model hoge

とすればapp/resources/hoge配下にファイルが出来ます。
なければ作成されます。

hoge_resource.rb
# frozen_string_literal: true

module Hoge
  class HogeResource < BaseResouce
    root_key :hoge

    attributes :id
  end
end

こっちもbase_resource.rbがなければできます。

とこんな感じ。

いざ

ジェネレータ作ります。

rails g generator alba

結果、lib/generators/alba配下に色々ファイルやらディレクトリができます。

まず触るのはalba_generator.rb

alba_generator.rb
class AlbaGenerator < Rails::Generators::NamedBase
  source_root File.expand_path('templates', __dir__)

  class_option :model, type: :string, default: 'sample'

  def create_alba_base_file
    base_resource_path = File.join('app/resources', 'base_resource.rb')
    
    unless File.exist?(base_resource_path)
      create_file base_resource_path, <<~RUBY
        class BaseResource
          include Alba::Resource
        end
      RUBY
    end
  end

  def create_alba_file
    template 'alba_template.erb', File.join('app/resources', class_path, "#{file_name}_resource.rb")
  end

  def run_rubocop
    generated_file_path = File.join('app/resources', class_path, "#{file_name}_resource.rb")
    system("bundle exec rubocop -a #{generated_file_path}", out: File::NULL, err: File::NULL)
  end

  private
  def model
    options['model']
  end
end

下記を見れば大体書いているので参考にしてください。なければAiに投げてください

https://railsguides.jp/generators.html

ポイントをかいつまんで説明すると

  • 上から下へ順に def で定義したパブリックなメソッドが実行されます
  • class_optionはコマンドの引数を追加したい場合設定します
  • class_optionで定義した引数はoptions['引数名']で取得します
  • templateメソッドは テンプレートファイルを第1引数に、それを元に作るファイルのパスを第2引数にとります
  • コード整形用にrubocop使ってます

くらいです。頭のいいみなさんなら秒なので多分平気です。

次にtemplates/alba_template.erbを作成し、記述します。

alba_template.erb
# frozen_string_literal: true
<% module_namespaces = class_path.map(&:camelize)%>
<% if module_namespaces.any? %>
<%= module_namespaces.map{|namespace| "module #{namespace}"}.join("\n") %>
  class <%= file_name.camelize %>Resource < BaseResouce
    root_key :<%= model %>

    attributes :id
  end
<%= "end\n"*module_namespaces.size%>
<% else %>
class <%= file_name.camelize%>Resource < BaseResouce
  root_key :<%= model %>

  attributes :id
end
<% end %>

てすれば、もうあとは rails g alba ファイル名 --model 対象のmodelを実行すればいけます。

終わりに

rubyの記述あれな場合は、上手い具合に改造しちゃってください

ということで。

Discussion