through:オプション以外でアクセスするために外部キーを追加してもよいか


ホテルの予約システムを実装しています。

[code]

      # 予約テーブル
      class Reservation < ActiveRecord::Base
        belongs_to :plan, inverse_of: :reservations
        delegate :room, to: :plan, allow_nil: true
      end
    
      # 予約プランテーブル
      class Plan < ActiveRecord::Base
        has_many :reservations, inverse_of: :plan
        belongs_to :room, inverse_of: :plans
      end
    
      # 部屋テーブル
      class Room < ActiveRecord::Base
        has_many :plans, inverse_of: :room
        has_many :reservations, through: :plans
      end
    
[/code]

このような関連の時、[ある部屋の予約状況を知りたい]時  
`ReservationsController`では

[code]

      @reservation = Room.find(params[:id]).reservations
    
[/code]

のようにしておくと 中間テーブルの役割を果たす`plans`が中でJoinされて  
[予約プランが一つでもないと予約状況が参照できない]状態となります。

そのため `reservations`に`room_id`を追加して直接参照したいのですが  
`plans`にも`room_id`があるためDB設計的に冗長なのではと感じてます。

この場合、どのように設計をすれば良いでしょうか。




要件に依ると思います。

今のモデルの設計だと、「プランなしでは予約できない」というルールに見えます。  
もし本当にそうだとしたら、「プランがないなら予約は参照できない」という状況でも困らないはずです。

ですが、「プランがなくても予約を参照したい」ということなので、実際は「プランなしでも予約は可能」なんだと思います。（ふつうのホテルの業務を想像してもたぶんそんな気がします）

さらにいうと、「部屋がプランを持つ」点に少し違和感があります。  
これはプランによって使える部屋が限定されるということなんでしょうか？

個人的な感覚でいうと、こんなモデル設計になる気がします。

  * Room has many reservations
  * Plan has many reservations
  * Reservation has room (必須：予約は必ず部屋を持つ)
  * Reservation has plan (任意：プランなしで予約されることもある)
  * 部屋とプランは直接関連しない

いずれにしても、部屋と予約とプランの関係性（業務ルール）を考えて、今のモデル構造が妥当かどうかを検証することが先かなと思います。  
妥当であれば、Reservationにroom_idを追加するのもアリだと思います。




要件に依ると思います。

今のモデルの設計だと、「プランなしでは予約できない」というルールに見えます。  
もし本当にそうだとしたら、「プランがないなら予約は参照できない」という状況でも困らないはずです。

ですが、「プランがなくても予約を参照したい」ということなので、実際は「プランなしでも予約は可能」なんだと思います。（ふつうのホテルの業務を想像してもたぶんそんな気がします）

さらにいうと、「部屋がプランを持つ」点に少し違和感があります。  
これはプランによって使える部屋が限定されるということなんでしょうか？

個人的な感覚でいうと、こんなモデル設計になる気がします。

  * Room has many reservations
  * Plan has many reservations
  * Reservation has room (必須：予約は必ず部屋を持つ)
  * Reservation has plan (任意：プランなしで予約されることもある)
  * 部屋とプランは直接関連しない

いずれにしても、部屋と予約とプランの関係性（業務ルール）を考えて、今のモデル構造が妥当かどうかを検証することが先かなと思います。  
妥当であれば、Reservationにroom_idを追加するのもアリだと思います。

