ActiveRecord has_many通过两个模型

时间:2018-03-14 17:42:09

标签: ruby-on-rails activerecord

我有以下背景:

4个型号:

  • 项目
  • 投资者
  • 订阅
  • ExternalSubscription

projectinvestorssubscriptions之间应有多个external_subscriptions

我目前有一个类似这样的方法:Investor.where(id: (subscription_ids + external_subscription_ids))

我的目标是建立has_many关系(并准确使用has_many activerecord功能)以获得相同的结果。 我该如何实现这一目标?它甚至可能吗?

谢谢!

Project

[Associations]
  has_many :subscriptions
  has_many :external_subscriptions

[Table description]
  create_table "projects", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
Investor

[Associations]
  has_many :subscriptions
  has_many :external_subscriptions

[Table description]
  create_table "investors", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
Subscription

[Associations]
  belongs_to :project
  belongs_to :investor

[Table description]
  create_table "subscriptions", force: :cascade do |t|
    t.integer "project_id"
    t.integer "investor_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["investor_id"], name: "index_subscriptions_on_investor_id"
    t.index ["project_id"], name: "index_subscriptions_on_project_id"
  end
ExternalSubscription

[Associations]
  belongs_to :project
  belongs_to :investor

[Table description]
  create_table "external_subscriptions", force: :cascade do |t|
    t.integer "project_id"
    t.integer "investor_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["investor_id"], name: "index_external_subscriptions_on_investor_id"
    t.index ["project_id"], name: "index_external_subscriptions_on_project_id"
  end

我在rails 5.0.x上

修改

我的真实模型比这更复杂。在这里,我只是展示关系以便于讨论,但我无法将subscriptionsexternal_subscriptions合并到同一个模型中。

2 个答案:

答案 0 :(得分:0)

由于您的订阅和external_subscriptions似乎不需要不同的信息(两个表都有相同的字段),我只使用一个模型和表,并根据表中的新字段对订阅进行分类。通过使用适当的范围,您可以轻松访问所有相关模型。

<强>项目

class Project < ApplicationRecord
  has_many :subscriptions
  has_many :external_subscriptions, -> { external }, class_name: "Subscription"
  has_many :normal_subscriptions, -> { normal }, class_name: "Subscription"
  has_many :investors, through: :subscriptions
  has_many :external_investors, through: :external_subscriptions, :source => :investor
  has_many :normal_investors, through: :normal_subscriptions, :source => :investor

end

<强>投资者

class Investor < ApplicationRecord
  has_many :subscriptions
  has_many :projects, through: : subscriptions
end

<强>订阅

class Subscription < ApplicationRecord
  belongs_to :project
  belongs_to :investor
  enum type: [ :external, :normal ]

  scope :external, -> { where(type: :external) }
  scope :normal, -> { where(type: :normal) } 
end

然后您可以访问不同的项目投资者:

project = Project.first.
project.investors #all
project.external_investors #only external
project.normal_investors #only normal

答案 1 :(得分:0)

由于@ MrYoshiji的评论,我通过执行UNION的SQL视图解决了我的问题。

这是POC:https://github.com/yoones/rails-has_many-through-view