1

Получил действительно интересную ситуацию со всеми отношениями has_one и belongs_to, когда Rails загружает свои зависимые модели обратным образом.Mutiple has_one того же класса

Давайте модель Couple с двумя родственными моделями того же класса, User:

class Couple < ActiveRecord::Base 
    has_one :male, class_name: "User" 
    has_one :female, class_name: "User" 
end 

class User < ActiveRecord::Base 
    belongs_to :couple 
end 

В этой ситуации, когда мы создаем Couple и присвоить ему два экземпляра User, мы получим в этом :

# create all the stuff 
couple = Couple.new 
he = User.create name: 'Bob' 
she = User.create name: 'Sara' 
couple.male = he 
couple.female = she 
couple.save 

# here's where the gap begins: 
couple.male.name # => 'Bob' 
couple.female.name # => 'Sara' 

# Ok, so far so good... 
Couple.find(couple.id).male.name # => 'Bob' 

# What's the ..?! 
Couple.find(couple.id).female.name # => 'Bob' 

И то, что я видел в консоли исполняющей все это, заключается в следующем:

> couple.female.name 
'Sara' 
# nothing happens as the model is loaded already 

> Couple.find(couple.id).female.name 
SELECT `couples`.* FROM `couples` WHERE `couples`.`id` = 2 LIMIT 1 
SELECT `users`.* FROM `users` WHERE `users`.`couple_id` = 2 LIMIT 1 
'Bob' 
# sure, here's the trouble! 

Хммм ... Это нехорошо ... Поиск через Интернет привел меня к следующему: я создал два класса: MaleUser и FemaleUser, оба из User. И изменил belongs_to :couple на belongs_to :couple, foreign_key: :his_id и ... :her_id. Тем не менее, тот же результат я видел на экране.

Мой вопрос: почему, черт возьми, это происходит и как правильно выполнять эту загрузку? Так что Couple.find(couple_id).she дал бы мне подходящий объект? Структура таблицы::

UPD

create_table :users do |t| 
    t.integer :couple_id 
    # ... 
end 

create_table :couples do |t| 
    t.integer :his_id 
    t.integer :her_id 
    # ... 
end 

Спасибо!

+0

Не могли бы вы также включить структуру таблиц миграции/SQL-таблицы для 'User' и' Couple'? – Pete

+0

@ Пойдем, если это поможет ... Тем не менее, нет ничего действительно интересного или сверхъестественного ... – shybovycha

ответ

0

Отношение к users в Couple должно быть отношением belongs_to, а не has_one. Например:

class Couple < ActiveRecord::Base 
    # ... 
    belongs_to :male, :class_name => 'User', :foreign_key => 'his_id' 
    belongs_to :female, :class_name => 'User', :foreign_key => 'her_id' 
end 

Это говорит о том, что ActiveRecord Couple имеет два User объектных отношений. Один из них называется male, который может быть найден с идентификатором, найденным в столбце his_id таблицы «Пара», а один из них - female, идентификатор которого находится в столбце her_id.

Принимая во внимание, что has_one будет искать эти данные отношений на таблице Users (которой не существует). Таблица пользователей ссылается только на couple_id, а не на пользователя или пользователя пользователя для отношения Couple.

+0

Но разве это имеет смысл? Как будто «пара принадлежит мужчинам и женщинам», это просто ... странно ... Хотя, полагаю, разработчики Rails добавили эти методы для этой вербальной правильности. – shybovycha

+0

Методы названы таким образом в ActiveRecord, чтобы указать, в каком классе сохраняется связь. В 90% случаев он хорошо работает с английским языком (комментарий принадлежит к сообщению в блоге и т. Д.), Но он никогда не прочитает полностью в 100% всех ситуаций. Альтернативой является использование Single Table Inheritance (STI), поэтому Couple has_one Female и has_one Male, а не несколько пользователей. Я не знаю, является ли это всего лишь гипотетическим примером, но важно помнить, что пара может также быть мужчиной/мужчиной или женщиной/женщиной. Так эффективно пара has_many Пользователи, которые также читают лучше – Pete

Смежные вопросы