has_one / has_many связывает рельсы с альтернативным идентификатором источника, отличным от первичного ключа - PullRequest
0 голосов
/ 22 октября 2018

у меня 3 модели.

Модель A принадлежит модели B, а модель B имеет много моделей C

с помощью through Я могу установить в классе A модель has_many :c,through: :b

Теперь всякий раз, когда я звонюa_instance.cs Было бы НЕОБХОДИМО ПРИСОЕДИНИТЬСЯ к таблице B. То, что я хочу, это прямая ассоциация A & C с использованием b_id в обоих классах A & C.

Итак, как я могу написать ассоциацию рельсов has_one / has_many без предложения through, если и у сущности-источника, и у места назначения один и тот же Foreign_key от 3-го лица?(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 голосов
/ 22 ноября 2018

Следуя вашему примеру классов 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 ...>

Официальная # стать (класс) документация может бытьнайдено здесь !

С другой стороны, того же эффекта можно добиться, создав экземпляр класса B и присвоив ему идентификатор, сохраненный в A.first.b_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 ...>
0 голосов
/ 20 ноября 2018

Например, модели учителя и ученика принадлежат группе, у учителя много учеников:

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
...