Rails 4 - has_one 和 belongs_to 抛出错误
Rails 4 - has_one and belongs_to throwing errors
我读过this,所以我明白其中的区别。
但我继承了一个引发奇怪行为的应用程序(我想,也许我错了,这是正常的)。
有 2 个模型:
class Pod < ActiveRecord::Base
has_one :pod_admin
end
class PodAdmin < ActiveRecord::Base
belongs_to :pod
end
在 rails 控制台中,我尝试了这个:
p = Pod.find(5)
它显示此 Pod 的 pod_admin_id
值为 14。这是正确的。
我尝试更改 PodAdmin:
p.pod_admin = PodAdmin.last
它抛出这个错误:
NoMethodError: undefined method pod_admin_id for #<PodAdmin:0x007fa401f1e710>
这是为什么?我错过了什么?
编辑
基于comments/answers,在不改变模型的情况下,我尝试了这个:
pa = PodAdmin.last
pa.pod = p
这很有效,我看到控制台 return 最后一个带有新 pod_id 的 PodAdmin。
但是
pa.save
和
p.save
都抛出与之前相同的错误。
如果我查看数据库架构,Pod table 有一个 pod_admin_id 字段,PodAdmin table 有一个 pod_id 字段。
我继承了这个架构,我只是想知道原始开发人员是否正确设置了它。当然,我应该能够从任一方向更新关系 - 这不是创建 has_one 和 belongs_to 的重点,所以你可以拥有这样的双向关系吗?
编辑 2
我发现了问题,这是我将此行添加到 PodAdmin table 而不是 Pod table:
validates :pod_admin_id, uniqueness: {scope: :id, message: 'The Pod already has a PodAdmin'}
抱歉 - 但如您所见,我在这里试图实现的是防止一个 Pod 拥有 2 个 PodAdmin。这个验证似乎没有实现。
我能做到:
p = Pod.find(5)
pa_last = PodAdmin.last
pa_first = PodAdmin.first
pa_last = p
pa_first = p
pa_last.save
pa_first.save
现在两个 pa 都具有相同的 pod_id。 我怎样才能防止这种情况发生?
编辑 3
经过大量阅读和测试并感谢@Anand 和@Spickerman,问题是之前的开发人员将外键放入两个 table 中(has_one
和 belongs_to
).只有 belongs_to table 应该有外键。此外,这种关系被错误地定义了。然而,解决这个问题并不能保证一个可靠的解决方案。我强烈建议其他有类似问题的人阅读 this。
外键始终属于具有 belongs_to
关联的模型。
在您的示例中 PodAdmin
belongs_to
Pod
,因此您的 pod_admins
table 应该有一个 pod_id
列。
或者您可以将模型更改为以下内容以反映您的数据库架构:
class Pod < ActiveRecord::Base
belongs_to :pod_admin
end
class PodAdmin < ActiveRecord::Base
has_one :pod
end
调用 PodAdmin.last.pod = p
而不是 p.pod_admin = PodAdmin.last
- 正如其他人提到的,pod_id 在 PodAdmin table 中,而不是相反。
更新:
根据对问题的更新,问题是因为你有两种方式的外键引用 - 你应该在 pod_admins table 或 pod_admin_id 中有 pod_id pods table,但不是两者。使用新迁移删除其中一个,然后重试
> bundle exec rails g migration RemovePodIdFromPodAdmins
# db/migrations/XXXX_remove_pod_admin_id_from_pods
def change
remove_column :pods, :pod_admin_id
end
bundle exec rake db:migrate
然后,按照上面的建议,调用
pa = PodAdmin.last
pa.pod = p
pa.save!
我读过this,所以我明白其中的区别。
但我继承了一个引发奇怪行为的应用程序(我想,也许我错了,这是正常的)。
有 2 个模型:
class Pod < ActiveRecord::Base
has_one :pod_admin
end
class PodAdmin < ActiveRecord::Base
belongs_to :pod
end
在 rails 控制台中,我尝试了这个:
p = Pod.find(5)
它显示此 Pod 的 pod_admin_id
值为 14。这是正确的。
我尝试更改 PodAdmin:
p.pod_admin = PodAdmin.last
它抛出这个错误:
NoMethodError: undefined method pod_admin_id for #<PodAdmin:0x007fa401f1e710>
这是为什么?我错过了什么?
编辑
基于comments/answers,在不改变模型的情况下,我尝试了这个:
pa = PodAdmin.last
pa.pod = p
这很有效,我看到控制台 return 最后一个带有新 pod_id 的 PodAdmin。
但是
pa.save
和
p.save
都抛出与之前相同的错误。
如果我查看数据库架构,Pod table 有一个 pod_admin_id 字段,PodAdmin table 有一个 pod_id 字段。
我继承了这个架构,我只是想知道原始开发人员是否正确设置了它。当然,我应该能够从任一方向更新关系 - 这不是创建 has_one 和 belongs_to 的重点,所以你可以拥有这样的双向关系吗?
编辑 2
我发现了问题,这是我将此行添加到 PodAdmin table 而不是 Pod table:
validates :pod_admin_id, uniqueness: {scope: :id, message: 'The Pod already has a PodAdmin'}
抱歉 - 但如您所见,我在这里试图实现的是防止一个 Pod 拥有 2 个 PodAdmin。这个验证似乎没有实现。
我能做到:
p = Pod.find(5)
pa_last = PodAdmin.last
pa_first = PodAdmin.first
pa_last = p
pa_first = p
pa_last.save
pa_first.save
现在两个 pa 都具有相同的 pod_id。 我怎样才能防止这种情况发生?
编辑 3
经过大量阅读和测试并感谢@Anand 和@Spickerman,问题是之前的开发人员将外键放入两个 table 中(has_one
和 belongs_to
).只有 belongs_to table 应该有外键。此外,这种关系被错误地定义了。然而,解决这个问题并不能保证一个可靠的解决方案。我强烈建议其他有类似问题的人阅读 this。
外键始终属于具有 belongs_to
关联的模型。
在您的示例中 PodAdmin
belongs_to
Pod
,因此您的 pod_admins
table 应该有一个 pod_id
列。
或者您可以将模型更改为以下内容以反映您的数据库架构:
class Pod < ActiveRecord::Base
belongs_to :pod_admin
end
class PodAdmin < ActiveRecord::Base
has_one :pod
end
调用 PodAdmin.last.pod = p
而不是 p.pod_admin = PodAdmin.last
- 正如其他人提到的,pod_id 在 PodAdmin table 中,而不是相反。
更新:
根据对问题的更新,问题是因为你有两种方式的外键引用 - 你应该在 pod_admins table 或 pod_admin_id 中有 pod_id pods table,但不是两者。使用新迁移删除其中一个,然后重试
> bundle exec rails g migration RemovePodIdFromPodAdmins
# db/migrations/XXXX_remove_pod_admin_id_from_pods
def change
remove_column :pods, :pod_admin_id
end
bundle exec rake db:migrate
然后,按照上面的建议,调用
pa = PodAdmin.last
pa.pod = p
pa.save!