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

# はじめに
みなさん、こんにちは　**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配下にファイルが出来ます。
なければ作成されます

```rb:tweets_with_images_resource.rb
# frozen_string_literal: true

class TweetsWithImagesResource < BaseResouce
  root_key :tweet

  attributes :id
end
```

```rb:base_resource.rb
class BaseResource
  include Alba::Resource
end

```

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

```
rails g alba hoge/hoge --model hoge
```

とすれば`app/resources/hoge`配下にファイルが出来ます。
なければ作成されます。
```rb: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`

```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`を作成し、記述します。

```rb: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の記述あれな場合は、上手い具合に改造しちゃってください

ということで。