1
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?

スコープ名にモデル名を用いたモデル設計とStyle/ClassAndModuleChildren (ネスト記法) のオートコレクションについて

Last updated at Posted at 2023-08-24

環境

対象 バージョン
Rubocop 1.56.1
TargetVersion 3.2
Rails 7.0.7

TL;DR

Style/ClassAndModuleChildren cop のオートコレクションは非安全である。特に既存のモデル名をスコープ名として使用している場合には、オートコレクションによってZeitwerkの定数解決に関するTypeErrorが発生する。

既存のモデル名をスコープ名としていた場合

以下の記事のように、既存のモデル名をスコープ名とするモデル設計を行っていたとする。

図1のようなディレクトリ構造で与えられている Post::Revision モデルに対して、Style/ClassAndModuleChildren cop (EnforcedStyle: nested) のオートコレクションを適用する 1

図1
app/models
├── post.rb
└── post
    └── revision.rb
app/models/post.rb
class Post; end
app/models/post/revision.rb
class Post::Revision; end

すると、post/revision.rb は次の変更を受ける。

app/models/post/revision.rb
- class Post::Revision; end
+ module Post
+     class Revision; end
+ end

この状態で bin/rails server などのコマンドを実行すると、「Post はモジュールではない」というメッセージを持つTypeErrorが発生する。

app/models/post/revision.rb:3:in `<main>': Post is not a module (TypeError)
app/models/project.rb:1: previous definition of Post was here

原因と解決

Zeitwerkは、まず post.rb を参照し post をクラスの定数であると解決する。その次に post/revision.rbmodule Post を見て、「postはモジュールではないよ!」と怒る2

したがって、次のように Post をモジュール定数からクラス定数として書き換えればよい。

app/models/post/revision.rb
- module Post
+ class Post
     class Revision; end
 end

そもそも……

そもそもRubocopドキュメントの『Style/ClassAndModuleChildren』節に、このcopのオートコレクションが非安全であり、手動による監督が必要であると明記されている。Rubocop はコンパクト記法 (Post::Revision) からネスト記法に移行する知識を (少なくとも現時点では) 持たないのだ。

Safety

Autocorrection is unsafe.

Moving from compact to nested children requires knowledge of whether the outer parent is a module or a class. Moving from nested to compact requires verification that the outer parent is defined elsewhere. RuboCop does not have the knowledge to perform either operation safely and thus requires manual oversight.

そもそもモデル設計に関して、admin などのクラス名とならないスコープ名は正しいものだが、「名前空間としてクラスを使」3ったモデル名は避けるべきだろう。たとえば、Railsドキュメントの『モデルを生成』には、「階層を指定」してモデルを生成するコマンドとして

rails generate model admin/account

が例示されている。つまり、階層を表す接頭辞 (スコープ名) に既存のモデル名を充てることは推奨されないということだ。

  1. コマンド rubocop -A <file> で Rubocop の自動訂正を適用できる。

  2. Zeitwerkの名前解決アルゴリズムについては、『Zeitwerkの壊し方』を参照してほしい。

  3. https://qiita.com/fursich/items/717a720d9f4465e4cbbb#5-%E5%90%8D%E5%89%8D%E7%A9%BA%E9%96%93%E3%81%A8%E3%81%97%E3%81%A6%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%92%E4%BD%BF%E3%81%86

1
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
1
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?