has_one / has_many与除主键之外的备用源ID的关联

时间:2018-10-22 08:09:35

标签: ruby-on-rails ruby ruby-on-rails-4 activerecord ruby-on-rails-5

我有3个模型。

模型A属于模型B,模型B具有许多模型C

使用through可以在模型A类has_many :c,through: :b中设置

现在,每当我调用a_instance.cs时,都将不必要地与表B联接。我想要的是在A和C类中都使用ACb_id直接关联。

那么当Source和Destination实体都具有与第3个实体相同的Foreign_key时,如何编写没有through子句的has_one / has_many rails关联? (此示例为b_id

class C
  belongs_to :b #b_id column is there in DB
end

class B
  has_many :cs
end

class A
  belongs_to :b #b_id column is there in DB
  has_many :cs , through: :b #This is the association in Question

  #WHAT I WANT TO DO. So something in place of primary_key which would fetch C class directly.
  has_many :cs ,class_name: 'C',foreign_key: 'b_id',primary_key: 'b_id'
end

2 个答案:

答案 0 :(得分:1)

例如,教师和学生模型属于组,教师有许多学生:

class Group < ApplicationRecord
  has_many :teachers
  has_many :students
end

class Teacher < ApplicationRecord
  belongs_to :group
  has_many :students, :foreign_key => 'group_id', :primary_key => 'group_id'
end

class Student < ApplicationRecord
  belongs_to :group
end

您可以像这样在一组中检索老师的学生:

teacher = Teacher.find(:teacher_id)
students = teacher.students

答案 1 :(得分:0)

下面以类A,B和C为例,仅更改类A的实现。

class A
  belongs_to :b

  def cs
    self.id = b_id
    b_cast = self.becomes(B)
    b_cast.cs
  end
end

控制台

A.first                    ==>#<A id: 105, b_id: 1 ...>
B.first                    ==>#<B id: 1 ...>
C.all                      ==>#<C id: 1, b_id: 1 ...>, 
                              #<C id: 2, b_id: 1 ...>, 
                              #<C id: 3, b_id: 1 ...>, 
                              #<C id: 4, b_id: 1 ...>



A.first.cs
A Load (0.2ms)  SELECT  "as".* FROM "as" ORDER BY "as"."id" ASC LIMIT ?  [["LIMIT", 1]]
C Load (0.1ms)  SELECT  "cs".* FROM "cs" WHERE "cs"."b_id" = ? LIMIT ?  [["b_id", 1], ["LIMIT", 11]]                 

A.first.cs                 ==>#<C id: 1, b_id: 1 ...>, 
                              #<C id: 2, b_id: 1 ...>, 
                              #<C id: 3, b_id: 1 ...>, 
                              #<C id: 4, b_id: 1 ...>

可以找到官方的#becomes(klass)文档 here

另一方面,创建类B的实例并为其分配存储在A.first.b_id中的ID可以达到相同的效果,如下所示:

B.new(id: A.first.b_id).cs
A Load (0.2ms)  SELECT  "as".* FROM "as" ORDER BY "as"."id" ASC LIMIT ?  [["LIMIT", 1]]
C Load (0.1ms)  SELECT  "cs".* FROM "cs" WHERE "cs"."b_id" = ? LIMIT ?  [["b_id", 1], ["LIMIT", 11]]                 

B.new(id: A.first.b_id).cs ==>#<C id: 1, b_id: 1 ...>, 
                              #<C id: 2, b_id: 1 ...>, 
                              #<C id: 3, b_id: 1 ...>, 
                              #<C id: 4, b_id: 1 ...>