🙄

【Rails】DBのテーブルに紐づかないモデルってどう作れば良いのん?

2023/04/25に公開

概要

DBに紐づかない、ただどこからでも利用できるユーティリティが欲しいときに

app/models/sample.rb
class Sample < ApplicationRecord
  def self.test
    'test'
  end
end

といった具合にモデルを作成していたんですが、これだけのためにApplicationRecordを継承するのは絶対に違うよな〜と思っていました。
というわけで、こういうときどうすればいいのかGPT-4に聞いてみました。

結論

ApplicationRecordを継承する代わりに、include ActiveModel::Modelを設定したモデルを作れば良い。

やりとり

質問:

SampleはDBにテーブルとして存在しないのですが、Railsで

class Sample < ApplicationRecord
  def self.test
    return "test"
  end
end

をより適切に直す方法はありますか?


答え:
Railsで実際のデータベーステーブルに関連付けられていないモデルを定義するには、ActiveModelモジュールを使用します。これにより、データベーステーブルがなくても、モデルのような構造を持つクラスを作成することができます。

以下のようにSampleクラスを書き換えてみてください。

class Sample
  include ActiveModel::Model

  def self.test
    return "test"
  end
end

include ActiveModel::Modelが追加されていることに注意してください。これにより、SampleクラスはActiveModelモジュールの機能を取り込み、Railsのモデルのような振る舞いをすることができます。ただし、データベースのテーブルとの関連付けは持ちません。

この変更により、SampleクラスはApplicationRecordから継承されず、データベーステーブルの存在を前提としないようになります。これで、Sample.testメソッドを使用する際に問題がなくなるはずです。


質問:

Sampleのようなinclude ActiveModel::Modelが設定されたファイルと、ApplicationRecordを継承したファイルは、ディレクトリでどう分けるべきでしょうか?


答え:

Railsアプリケーションでは、通常app/modelsディレクトリにモデルを格納します。ただし、ActiveModel::Modelを使用したモデルとApplicationRecordを継承したモデルを分ける場合、ディレクトリ構造を整理することが役立ちます。

以下のようにディレクトリを分けることが一般的です:

app/modelsディレクトリには、ApplicationRecordを継承した通常のActiveRecordモデルを格納します。これらのモデルはデータベーステーブルに関連付けられています。

app/models/non_database(またはapp/models/active_modelsapp/models/non_persistentなど、適切な名前で)ディレクトリを作成し、ActiveModel::Modelを使用したモデルを格納します。これらのモデルはデータベーステーブルに関連付けられていません。

この構造にしたがってディレクトリを分けることで、プロジェクトの構造が整理され、非データベースモデルとデータベースモデルを簡単に識別できます。

ただし、Railsが新しく作成したディレクトリを自動的に読み込むようにするために、オートロードのパスを設定する必要があります。

config/application.rbファイルを開いて、Applicationクラスのconfigブロック内に、以下のように新しいディレクトリを追加してください。

config.autoload_paths += %W(#{config.root}/app/models/non_database)

これにより、Railsはapp/models/non_databaseディレクトリ内のファイルも自動的に読み込むようになります。この変更を反映させるために、Railsアプリケーションを再起動してください。

この方法で、ActiveModel::Modelを使用したモデルとApplicationRecordを継承したモデルを適切に分けることができます。

Discussion