在两个不同的数据库上通过ActiveRecord has_many遇到关系问题

时间:2019-01-23 20:39:51

标签: ruby-on-rails activerecord has-many-through ruby-on-rails-4.2

我正在尝试在两个不同的数据库上建立has_many :through关系,并遇到问题。

我的模型如下:

公司

# this model lives in database main_db
class Company < ActiveRecord::Base
  has_many :company_custom_plans
  has_many :custom_plans, through: :company_custom_plans
end

custom_plan

# this model lives in database other_app_db
class CustomPlan < ActiveRecord::Base
  has_many :company_custom_plans
  has_many :companies, through: :company_custom_plans
end

关节模型

# this model lives in other_app_db
class CompanyCustomPlan < ActiveRecord::Base
  belongs_to :custom_plan
  belongs_to :company
end

### Schema ###
#  create_table "company_custom_plans", force: :cascade do |t|
#    t.integer "company_id",     limit: 4, null: false
#    t.integer "custom_plan_id", limit: 4, null: false
#  end

因此,它在Company模型上非常有效,但是当尝试在CustomPlan上使用此关系时,出现错误,因为has_many:through在company_custom_plans中查找main_db而不是{ {1}}

示例:

other_app_db

我尝试使用has_many:through的不同选项(例如设置ccp = CompanyCustomPlan.create!(company: company, custom_plan: custom_plan) company.company_custom_plans == [ccp] # true company.custom_plans == [custom_plan] # true custom_plan.company_custom_plans == [ccp] # true custom_plan.companies # error ActiveRecord::StatementInvalid: Mysql2::Error: Table 'main_db.company_custom_plans' doesn't exist: SHOW FULL FIELDS FROM `company_custom_plans` ),但无法弄清楚如何完成这项工作。

谢谢

2 个答案:

答案 0 :(得分:3)

命名has_many through:关联的联接模型(或具有复合名称的一般模型)时,对于模型,应遵循SingularSingular的格式,对于表应遵循singular_plural的格式。因此,您应该命名模型CompanyCustomPlan和表company_custom_plans。这与has_and_belongs_to_many不同。

例如:

class User
  has_many :user_courses
  has_many :courses, though: :user_courses
end

class Course
  has_many :user_courses
  has_many :users, though: :user_courses
end

class UserCourse
  belongs_to :user
  belongs_to :course
end

这将正确地将关联映射到UserCourse类。如果我们使用has_many :users_courses,由于ActiveRecord从关联中派生类名称的方式,我们将得到NameError: uninitialized constant Users::Courses-复数单词被解释为模块!

您当然可以通过提供class_name选项来覆盖此问题,但是首先遵循约定可能是一个更好的主意,除非您有充分的理由不这样做。

当然,如果存在可以更好地描述域的内容,则可以为连接模型使用完全不同的名称-例如Enrollment而不是UserCourse

答案 1 :(得分:0)

我最终想出了如何强制has_many :through在此stackoverflow answer之后使用正确的数据库。

class CompanyCustomPlan < ActiveRecord::Base

  self.table_name = "#{ActiveRecord::Base.connection.current_database}.company_custom_plans"

  belongs_to :custom_plan
  belongs_to :company
end