後へ      Topへ      次へ

モデル共通コード

Scaffold で作成した View では、
外部キー参照(references) のデータは、
ID の数値をそのまま扱う状態になっています。
例えば、Cabinet 編集画面の Floor が 1 になっている感じ。
これだと 1 が何者か分からないので、
“1F” と表示されるように修正しましょう。

参考リポジトリ: https://github.com/Bonv-dev/book_mgmt/commit/289fb87

\models\concerns

references データの編集は複数のモデルで行うため、
共通で使用できるコードを書きましょう。

\app\models\concerns フォルダに common_scopes.rb というファイルを追加します。
中身は、

module CommonScopes
  extend ActiveSupport::Concern

  included do
    scope :enabled_only, -> { where(enabled: true) }
  end

  class_methods do
    # データ表示用 (全データを持つ)
    def name_list
      self.pluck(:id, :name).to_h
    end

    # データ編集用 (有効なデータのみ)
    def name_options
      self.enabled_only.pluck(:name, :id).to_h
    end
  end
end

とします。
中身を順に説明します。

モデルクラス側に埋め込む際には、

class Book < ApplicationRecord
  include CommonScopes
end

のようにします。

module

module は Ruby の機能で、クラスに追加できる機能のかたまりです。
new はできず、クラスに埋め込んで使います。
クラスに新しい機能を追加する働きを持ちます。

具体的な埋め込み方は、後述します。

concerns フォルダ

\app\models\concerns フォルダは Rails 標準で用意されています。
モデル用 module の定義ファイルを置く場所です。
モデルクラスの定義ファイルを置く \app\models フォルダと分けて、
module を管理しやすくします。

extend ActiveSupport::Concern

ActiveSupport::Concern は、
module をクラスに埋め込みやすくする、ActiveSupport のライブラリです。
これを、extend で該当モジュール (今回なら CommonScopes) に組み込みます。

使用する際には、 クラス側、例えば Book クラス内で、
include CommonScopes
のようにして該当モジュールを追加します。

included do~end

このブロック内にメソッドを入れておくと、
メソッドがインクルード先に埋め込まれた状態で動作します。

extend ActiveSupport::Concern 必須です。

scope

ActiveRecord の機能の一つです。
モデルの条件式 (クエリ) に名前を付け、
その名前をメソッドのように使用できるようにします。

scope :enabled_only, -> { where(enabled: true) } なら、
where(enabled: true) に enabled_only という名前を付け、
Book.enabled_only のように使えます。
(Book データから、enabled カラムの値が true のものだけを抽出します。)

引数を渡したい場合は、
例えば、
scope :enabled_only, -> (flag){ where(enabled: flag) }
のようにします。
Book.enabled_only(true) のように使えます。

class_methods do~end

このブロック内にメソッドを入れておくと、
メソッドがインクルード先に埋め込まれた状態でクラスメソッドとして使用できます。

リスト

CommonScopes モジュールに書いた name_list メソッドを使います。
CommonScopes を include したモデル、
例えば、Category なら、Category.name_list になります。
name_list の中身が self.pluck(:id, :name).to_h なので、
Category データから id と name カラムのペアを抽出し、
to_h で {id=>name} の hash が生成されます。

表示画面 \app\views\books\_book.html.erb 内で
@category_list[book.category_id] としているので、
該当 @book の category_id に該当する name が表示されることになります。

オプション

CommonScopes モジュールの name_options も、
name_list と同様の流れで View に適用します。

こちらは編集画面 \app\views\books\_form.html.erb 内、
form.select で使うため {:name=>:id} と name_list からキー・値が入れ替わっています。

Category には enabled (有効・無効)カラムがあります。
編集画面で無効なデータを選択されては困るので、
name_options は enabled_only で絞っています。
表示画面では、過去の無効なデータも表示できないと困るので、
name_list は enabled_only を通しません。

中級

注意すべきは、
同じ name が複数ある場合です。
Step には、1F にも 2F にも “S00” があります。
name_options で name をキーにしてしまうと、
後で出てきた name だけが残ってしまいます。
重複を避けるには、
form.select :step_id, @step_options を、
form.collection_select :step_id, Step.enabled_only, :id, :name
に変えるなどの工夫が必要です。

これで重複する項目も消えずにリストアップされはしますが、
どれがどの ID なのか分からないので、根本解決にはなりません。
サンプルプログラムでは、全く別の方法 ( StimulusTurbo Stream ) を使って解決します。


後へ      Topへ      次へ