Rails - build_association不适用于has_one和belongs_to关系

时间:2010-01-11 06:14:01

标签: ruby-on-rails activerecord associations

我有两个型号

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 个答案:

答案 0 :(得分:9)

根据您的模特关联,SubscriptionClient的孩子。

如果您先创建订阅然后根据第一个示例创建客户端,则Rails无法在client_id表中设置subscriptions外键值,因为此时您还没有' t创建了客户端记录,因此没有任何内容可以与订阅相关联。这就是为什么你必须首先创建父记录(即客户端),然后使用build_subscription方法将其与子订阅记录相关联。

答案 1 :(得分:3)

它无法双向工作,父级可以使用build_association方法构建子级,但反之亦然。

阅读:http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_one

答案 2 :(得分:1)

在我的项目中,我有许多类似的关联,但我经常禁止将client_id设置为null,因此我无法在没有父对象的情况下创建子对象。

尝试:

sub = Subscription.new
sub.build_client
sub.save

它将创建并保存两个对象。

答案 3 :(得分:1)

这似乎已在Rails 4.2.5或更早版本中得到修复。 (我不确定修复程序的最早版本是什么。我只测试了4.2.5。)

保存父级后,插入父级记录后,会自动执行更新,将父级ID添加到子级记录中。

但是,我还没有找到有关此行为,相关代码或自动化测试的任何文档,因此我不确定是否故意修复此行为并且应该依赖此行为。最好在这里的其他答案中坚持使用解决方案。

在Rails 4.2.5中,似乎仍然打破了has_many

答案 4 :(得分:0)

在其中一条评论中,您会问为什么build_client方法存在。当您保存客户端然后检查sub上的client_id时,它是nil,但是如果您还要调用

sub.save(validate: false)

然后检查sub上的client_id,它会存在。因此,虽然它需要额外的保存,但仍然可以为sub设置外键。