2016-05-13 79 views
1

我已阅读this,所以我明白其中的差异。Rails 4 - has_one和belongs_to投掷错误

但我继承了一个抛出奇怪行为的应用程序(我想,也许我错了,这是正常的)。

有2种型号:

class Pod < ActiveRecord::Base 
    has_one :pod_admin 
end 

class PodAdmin < ActiveRecord::Base 
    belongs_to :pod 
end 

在轨控制台,我尝试这样做:

p = Pod.find(5) 

,它表明该吊舱具有pod_admin_id值的14。这是正确的。

我试图改变PodAdmin:

p.pod_admin = PodAdmin.last 

,并抛出这个错误:

NoMethodError: undefined method pod_admin_id for #<PodAdmin:0x007fa401f1e710> 

这是为什么?我错过了什么?

编辑基于的意见/回答

,在不改变模型,我尝试这样做:

pa = PodAdmin.last 
pa.pod = p 

和这样的作品,我看到控制台返回最后PodAdmin用新pod_id。

pa.save 

p.save 

都抛出同样的错误了。

如果我看一下数据库模式,Pod表具有pod_admin_id字段,而PodAdmin表具有pod_id字段。

我继承了这个模式,我只是想知道原始开发者是否正确设置了这个模式。当然,我应该能够从任一方向更新关系 - 是不是创建has_one和belongs_to的关键,所以你可以有这样的双向关系?

EDIT 2

我发现这个问题,这是我已经添加了此行PodAdmin表,而不是吊舱表:

validates :pod_admin_id, uniqueness: {scope: :id, message: 'The Pod already has a PodAdmin'} 

道歉 - 但正如你所看到的,是什么我想在这里实现的目的是防止Pod有2个PodAdmins。这验证似乎并没有达到。

我可以这样做:

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的问题是,以前的开发人员把一个外键到这两个表(在has_onebelongs_to)。只有belongs_to表应该有一个外键。此外,这种关系被定义为错误的方式。但是,解决这个问题并不能保证可靠的解决方案。我强烈建议其他类似问题的人阅读this

+2

你做错了。随着你的关联设置,“pod_admins”表应该有'pod_id'。 – Pavan

+0

@Pavan是对的,你需要'pod_admins'表上的'pod_id',或'Pod'''属于':pod_admin'而'PodAdmin'' has_one:pod' –

+0

pod_admins表有一个pod_id字段。我更新了我的问题来解释 - 似乎我无法从任何一方更新关系。 – rmcsharry

回答

1

相反的p.pod_admin = PodAdmin.last,叫PodAdmin.last.pod = p - 正如其他人所提到的,pod_id在PodAdmin表,而不是其他方式。

更新:

基于更新问题,这个问题是因为你有外键引用两种方式 - 您应该已经pod_id在pod_admins表或豆荚表pod_admin_id,但不能同时使用。删除其中一个与新的迁移,然后再次尝试

> 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! 
+0

由于belongs_to在PodAdmin模型中,我不应该保留该外键,而是从has_one一侧移除foreign_key(即从Pod表中删除PodAdminID)? – rmcsharry

+0

我从Pods表中删除了pod_admin_id。我仍然可以给2 PodAdmins相同的Pod。这是坚果。 – rmcsharry

+0

是的,@ rmcsharry - 我正在更新回应以表明这一点。如果您从pod表中删除pod_admin_id,它仍然允许两个pod_admin拥有相同的pod,因为'pod belongs_to pod_admin'表示每个实例可以属于某个pod。但是,因为你有'pod_admin has_one pod',pod.pod_admins将是未定义的,而pod.pod_admin将被定义(尽管它将返回的是未定义的)。 – Anand

1

外键始终属于与belongs_to关联的型号。

在您的例子PodAdminbelongs_toPod,因此您pod_admins表应该有一个pod_id列。

或者,你可以改变你的模型如下,以反映您的数据库模式:

class Pod < ActiveRecord::Base 
    belongs_to :pod_admin 
end 

class PodAdmin < ActiveRecord::Base 
    has_one :pod 
end 
+0

pod_admins表确实有一个pod_id列。我用更多的信息更新了这个问题。 – rmcsharry

+0

外键只能存在于拥有belongs_to的模型的表中。另一个表格不能有这样的列(并且也不需要该列)。要防止两个PodAdmin拥有相同的Pod,请选择我的第二个版本,并在belongs_to关联时切换方向。 – spickermann

+0

谢谢,我试过了,从'has_one'表中删除了列。我仍然可以将多个PodAdmin分配给Pod。我会尝试你的第二个版本,但是很确定可以给每个PodAdmin分配多个Pod,因为这不是1-n关系,所以不应该被允许。看来我必须在数据库级执行此限制。 – rmcsharry