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

```

      # 予約テーブル
      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
    
```

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

```

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

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

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

この場合、どのように設計をすれば良いでしょうか。
CC BY-SA 3.0
2015-09-14T13:30:26.617
16601
2015-09-15T00:52:56.920
2015-09-15T00:06:42.907
9177
9177
question
ruby-on-rails rails-activerecord
through:オプション以外でアクセスするために外部キーを追加してもよいか
要件に依ると思います。

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

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

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

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

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

いずれにしても、部屋と予約とプランの関係性（業務ルール）を考えて、今のモデル構造が妥当かどうかを検証することが先かなと思います。  
妥当であれば、Reservationにroom_idを追加するのもアリだと思います。
CC BY-SA 3.0
2015-09-14T19:15:28.347
16609
2015-09-14T19:15:28.347
85
16601
answer
`Reservation`に`room_id`を追加した場合、`Reservation`と`Room`の間に`Reservation`-`Plan`-`Room`という関連と、`Reservation`-`Room`という2経路の関連が出来ることになるので、この整合性を担保する必要があります。

整合性の担保は

  * モデルを使う側に押しつける
  * モデルの側でコールバックなどを使って実現する
  * DB側でトリガなどで実現する

等考えられますが、いずれにせよ結構面倒です

複数経路での関連が生じるのは直ちにNGではないのですが、本当に必要性があるのか、設計で回避できないのかは検討する必要があるでしょう。

* * *

ところで、このモデル設計では、一般的には可能でなければならないはずの「一つの予約で複数の部屋を申し込む」ということが管理できません。また「予約プラン」というのが単なる中間テーブルなのか、いわゆる「スタンダードプラン」とか「レディースプラン」とかの「プラン」なのかどちらとも読み取れるのですが、どちらであるにしても違和感があります。そもそもの設計に問題があるような気がします。
CC BY-SA 3.0
2015-09-15T00:52:56.920
16611
2015-09-15T00:52:56.920
5793
16601
answer