有额外列的Rails多对多

时间:2017-11-09 15:40:37

标签: ruby-on-rails many-to-many

所以我有这些表:

<mat-table [dataSource]="dataSource">

  <ng-container matColumnDef="name">
    <mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
    <mat-cell *matCellDef="let project">{{project.name}}</mat-cell>
  </ng-container>

  <ng-container matColumnDef="key">
    <mat-header-cell *matHeaderCellDef> Key </mat-header-cell>
    <mat-cell *matCellDef="let project">{{project.Key}}</mat-cell>
  </ng-container>

  <ng-container matColumnDef="reason">
    <mat-header-cell *matHeaderCellDef> reason </mat-header-cell>
    <mat-cell *matCellDef="let project">{{project.reason}}</mat-cell>
  </ng-container>

  <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
  <mat-row *matRowDef="let row; column: displayedColumns;"></mat-row>

</mat-table>

我这样做了,当我打电话给Room.find(1)。用户我得到了房间里所有用户的清单。但是,我还希望能够调用类似Room.find(1).admins的内容并获取管理员用户列表(其中,room_users中的is_admin为true)。我该怎么办?

感谢您的时间!

2 个答案:

答案 0 :(得分:0)

您可以在proc关系中定义has_many来设置SQL子句,例如ORDERWHERE

# room.rb
has_many :rooms_users, class_name: 'RoomsUser'
has_many :users, through: :rooms_users
has_many :admins, 
  proc { where(rooms_users: { is_admin: true }) },
  through: :rooms_users,
  class_name: 'User',
  source: :users

# user.rb
has_many :administrated_rooms,
  proc { where(rooms_users: { is_admin: true }) },
  through: :rooms_users,
  class_name: 'Room',
  source: :rooms

您可以使用scope模型中定义的简单RoomsUser来简化此操作,例如:

# rooms_user.rb
scope :as_admins, -> { where(is_admin: true) }

并在proc中使用它:

# user.rb
has_many :administrated_rooms,
  proc { as_admins },
  through: :rooms_users,
  class_name: 'Room',
  source: :rooms

source选项解释:

  

使用source: :users,我们告诉Rails在RoomsUser模型上使用名为:users的关联(因为它是:rooms_users使用的模型)。< / p>

(来自Understanding :source option of has_one/has_many through of Rails

答案 1 :(得分:0)

您想使用has_many through:代替has_and_belongs_to_many。两者都定义了多个到多个关联,但has_many through:使用模型作为连接行。

缺乏模型会使has_and_belongs_to_many非常有限。由于间接创建了行,因此无法直接查询连接表或添加其他列。

class User < ApplicationRecord
  has_many :user_rooms
  has_many :rooms, through: :user_rooms
end

class Room < ApplicationRecord
  has_many :user_rooms
  has_many :users, through: :user_rooms
end

class UserRoom < ApplicationRecord
  belongs_to :user
  belongs_to :room
end

您可以使用现有架构,但需要使用migration将表users_rooms重命名为user_rooms - 否则rails会将类名称取消为Rooms::User。< / p>

class RenameUsersRooms < ActiveRecord::Migration[5.0]
  def change
    rename_table(:users_rooms, :user_rooms)
  end
end
  

但是,我也希望能够打电话   Room.find(1).admins并获取管理员用户列表(其中   rooms_users中的is_admin为true)。我该怎么做?

您想使用左内连接:

User.joins(:user_rooms)
    .where(user_rooms: { room_id: 1, is_admin: true })

要将其滚动到类中,您可以设置与应用范围的关联:

class Room < ApplicationRecord
  has_many :user_rooms
  has_many :users, through: :user_rooms
  has_many :user_room_admins, class_name: 'UserRoom', ->{ where(is_admin: true) } 
  has_many :user_room_admins, through: :user_rooms, 
    class_name: 'User',
    source: :user
end