Rails Active Record:如何加入三个表?

时间:2018-01-31 11:50:47

标签: mysql ruby-on-rails activerecord

我有三张桌子,如下所示:

enter image description here

广告客户模式:

class Advertiser < ActiveRecord::Base
 has_many :advertisers_account_groups

AdvertisersAccountGroup模型

class AdvertisersAccountGroup < ActiveRecord::Base
 belongs_to :advertiser
 belongs_to :v2_account_account_group, class_name: 'V2Account::AccountGroup', foreign_key: 'account_group_id'

我想知道哪个广告客户属于v2_account_account_groups  并希望获得v2_account_account_groups。姓名

期望的输出: enter image description here

我尝试了什么;

Advertiser.where(media_type: "line").joins(advertisers_account_groups,v2_account_account_groups)

但它不起作用

2 个答案:

答案 0 :(得分:3)

在我看来,您当前的设置使用AdvertisersAccountGroup作为连接表;因此,我建议使用has_many :through关联。

要做到这一点,您只需要按如下方式切换模型:

class Advertiser < ActiveRecord::Base
  has_many :v2_account_account_groups, through: :advertisers_account_groups
  has_many :advertisers_account_groups
  ...
end

class V2Account::AccountGroup < ActiveRecord::Base
  has_many :advertisers, through: :advertisers_account_groups
  has_many :advertisers_account_groups
  ...
end

class AdvertisersAccountGroup < ActiveRecord::Base
  belongs_to :advertiser
  belongs_to :v2_account_account_group, class_name: 'V2Account::AccountGroup', foreign_key: 'account_group_id'
  ...
end

这样您就可以根据需要查询advertiser,即advertiser.v2_account_account_groups

但是,此关联在广告客户和v2帐户组之间是多对多关系 - 因此,您无法调用advertiser.v2_account_account_groups.name,因为advertiser.v2_account_account_groups会返回收藏品而非而不是一个记录。

您可以使用advertiser.v2_account_account_groups.map(&:name)(以获取所有群组和名称的数组)或advertiser.v2_account_account_groups.first&.name,但听起来好像您可能需要重新构建数据,如果广告客户应该只有一个v2帐户组。

这是否有意义和听起来像你正在寻找的?如果您有任何疑问,请与我联系。

编辑:

根据您的评论,我认为您应该能够按如下方式构建查询:

Advertiser.includes(advertiser_account_groups: : v2_account_account_group)
          .where(advertiser_account_groups: { v2_account_groups: { name: "something" } })

这听起来像你正在寻找的吗?

有几点需要注意:

  • 在引用includes中的关联时,您希望使用关联名称
  • ,将这些插入where子句时,您需要使用完整的表名,因为它们在数据库中(可通过Model.table_name搜索)

此外,在您的评论中,您引用了添加media_type: "line",其中还包括:

Advertiser.includes(advertiser_account_groups: : v2_account_account_group)
          .where(media_type: "line", advertiser_account_groups: { v2_account_account_groups: { name: "something" } })

在您的代码中构建此代码的最佳方式可能是广告客户模型中的范围,例如:

scope :by_v2_group_name, -> (name) { includes(advertiser_account_groups: :v2_account_account_group)
                               .where(media_type: "line", advertiser_account_groups: { v2_account_account_groups: { name: "something" } }) }

scope :by_v2_group_name, (lambda do |name| 
  includes(advertiser_account_groups: :v2_account_account_group)
  .where(media_type: "line", advertiser_account_groups: { v2_account_account_groups: { name: "something" } })
end)

然后,您可以保持代码清洁并调用Advertiser.by_v2_group_name("something")

让我知道你是如何继续这样做的,我们将根据需要对其进行处理:)

答案 1 :(得分:-1)

只有当您不需要连接表的模型时,此答案才有意义  advertiser_account_gourps (如果您在该联接表上没有advertiser_idaccount_gourp_id之外的任何其他属性 - 通常不需要它)

虽然@ SRack的答案是使用has_many :through关联,但我认为您可以使用简单的多对多关联(has_and_belongs_to_many),因为在您的图片中我可以看到连接表只有相关表格的ids(除非您确实需要id列 - >;在这种情况下,请使用@ SRack的解决方案!)

class Advertiser < ActiveRecord::Base
  has_and_belongs_to_many :advertisers_account_groups

class AccountGroup < ActiveRecord::Base
  has_and_belongs_to_many :advertisers

然后你可以使用它们来获取它们:

advertiser = Advertiser.first
advertiser.account_groups #to get account groups of that advertiser

反之亦然:

account_group = AccountGroup.first
account_group.advertisers # to get advertisers of that account group
  • @ SRack的评论是正确的!我把它改成了HABTM协会!

在这种情况下,您需要创建一个迁移来创建连接表:

rails g migration CreateJoinTableAdvertiserAccountGroup advertiser account_group

此表格仅包含相关的advertiser_idaccount_group_id

您不需要创建模型并处理该表上的内容,rails将为您填充该表。