Techioz Blog

列の値に基づいたカスタム has_one

概要

Rails の初心者は、ActiveRecords を使用してこの関係をモデル化できるかどうか疑問に思っていました。

次のモデルがあります(簡略化):

User:
 - name
 - email 
Client:
 - name
 - address

そして、これらのテーブルの両方に関連するモデルの出席者がありますが、type 列があります。

| id | join_type | join_id | 
|----|-----------|---------|
|  1 |    user   |    1    |
|  2 |   client  |    1    |

has_one リレーションを使用してアクティブなレコードでそれをモデル化する方法はありますか?

何かのようなもの:

class Attendee < ApplicationRecord

    # OBVIOUSLY DOESNT WORK
    has_one :user, ->() { where(join_type: 'user') }, :class_name => 'User'
    has_one :client, ->() { where(join_type: 'client') }, :class_name => 'Client'

end

つまり、正しい左結合が生成されるのでしょうか?

ありがとう

解決策

この構造で出席者テーブルを作成します

class CreateAttendees < ActiveRecord::Migration[7.0]
  def change
    create_table :attendees do |t|
      t.timestamps
      t.string :linked_object_type
      t.bigint :linked_object_id
    end

    # optinal
    add_index :attendees, %i[linked_object_type linked_object_id]
  end
end

# app/models/client_attendee.rb
class Attendee < ApplicationRecord
  belongs_to :linked_object, polymorphic: true, foreign_type: :linked_object_type
end

次に、次のようにAttendeeインスタンスからユーザー/クライアントにアクセスできます

   attendee = Attendee.first
   linked_object = attendee.linked_object # Depends on linked object type it will return the relative model instance

ユーザー/顧客から出席者にアクセスしたい場合は、次のように定義できます。

# frozen_string_literal: true

# This model is used to store user data
class User < ApplicationRecord
  has_many :attendees, as: :linked_object, linked_object_type: 'User' # You can scope it yourself, and define has_one depends on your design. 
end