Rails - build_association не работает для отношений has_one и own_to - PullRequest
8 голосов
/ 11 января 2010

У меня две модели

class Subscription < ActiveRecord::Base
  belongs_to :client
end

class Client < ActiveRecord::Base
  has_one :subscription
end

но когда я пытаюсь создать родителя от ребенка, например sub.build_client внешний ключ не установлен, например

>> sub = Subscription.new
=> #<Subscription id: nil, token: nil, user_id: nil, created_at: nil, updated_at: nil, cancelled: nil, active: nil, client_id: nil>
>> sub.save(false);
?> client = sub.build_client
=> #<Client id: nil, server_id: nil, ip: nil, created_at: nil, updated_at: nil>
>> client.save(false)
=> true
>> sub.client_id
=> nil
>> sub
=> #<Subscription id: 4, token: nil, user_id: nil, created_at: "2010-01-11 06:07:45", updated_at: "2010-01-11 06:07:45", cancelled: nil, active: nil, client_id: nil>

Это работает, если я делаю client.build_subscription

?> client = Client.new
=> #<Client id: nil, server_id: nil, ip: nil, created_at: nil, updated_at: nil>
>> client.save(false)
=> true
>> sub = client.build_subscription
=> #<Subscription id: nil, token: nil, user_id: nil, created_at: nil, updated_at: nil, cancelled: nil, active: nil, client_id: 4>
>> sub.save(false)
=> true
>> sub
=> #<Subscription id: 5, token: nil, user_id: nil, created_at: "2010-01-11 06:09:32", updated_at: "2010-01-11 06:09:32", cancelled: nil, active: nil, client_id: 4>
>> client
=> #<Client id: 4, server_id: nil, ip: nil, created_at: "2010-01-11 06:09:02", updated_at: "2010-01-11 06:09:02">
>> ^C

Я потратил 3 часа и быстро никуда не попал. Может кто-нибудь объяснить, что я делаю не так, что нужно проверить и т. Д.

Ответы [ 5 ]

9 голосов
/ 11 января 2010

Согласно вашим модельным ассоциациям, Subscription является потомком Client.

Если вы сначала создаете подписку, а затем создаете клиента в соответствии с вашим первым примером, Rails не может установить значение внешнего ключа client_id в таблице subscriptions, поскольку на тот момент вы еще не создали клиента запись, так что нечего связывать с подпиской. Вот почему вы должны сначала создать родительскую запись (то есть клиент), а затем связать ее с дочерней записью подписки, используя метод build_subscription.

3 голосов
/ 11 января 2010

это не работает в обоих направлениях, родитель может построить ребенка с помощью метода build_association, но не наоборот.

прочитано: http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_one

1 голос
/ 02 января 2016

Это, кажется, было исправлено в Rails 4.2.5 или более ранней версии. (Я не уверен, что самая ранняя версия с исправлением. Я только протестировал 4.2.5.)

Когда родительский элемент сохраняется, после вставки родительской записи автоматически выполняется обновление для добавления родительского идентификатора в дочернюю запись.

Однако я не нашел никакой документации об этом поведении, соответствующем коде или автоматических тестах, поэтому я не уверен, было ли оно намеренно исправлено, и на это поведение следует полагаться. Возможно, лучше придерживаться решений в других ответах здесь.

Это также, похоже, все еще не работает для has_many в Rails 4.2.5.

1 голос
/ 11 января 2010

В моих проектах у меня много похожих ассоциаций, но я часто запрещаю устанавливать client_id в значение null, поэтому я не могу создать дочерний объект без родительского объекта.

Попытка:

sub = Subscription.new
sub.build_client
sub.save

Создает и сохраняет оба объекта.

0 голосов
/ 27 апреля 2013

В одном из комментариев вы спрашиваете, почему существует метод build_client. Когда вы сохраняете клиента и затем проверяете client_id на sub, он равен nil, но если бы вы также вызвали

sub.save(validate: false)

и затем проверил client_id на sub, он будет существовать. Поэтому, хотя для этого потребовалось дополнительное сохранение, он по-прежнему творит волшебство настройки внешнего ключа для sub.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...