rmcsharry rmcsharry - 5 months ago 8x
Ruby Question

Rails 4 - has_one and belongs_to throwing errors

I have read this, so I do understand the difference.

But I have inherited an app that is throwing strange behaviour (I think, perhaps I am wrong and this is normal).

There are 2 models:

class Pod < ActiveRecord::Base
has_one :pod_admin

class PodAdmin < ActiveRecord::Base
belongs_to :pod

In the rails console, I tried this:

p = Pod.find(5)

and it shows this Pod has a
value of 14. This is correct.

I tried to change the PodAdmin:

p.pod_admin = PodAdmin.last

and it throws this error:

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

Why is that? What am I missing?


Based on comments/answers, without changing the models, I tried this:

pa = PodAdmin.last
pa.pod = p

and that works, I see the console return the last PodAdmin with a new pod_id.





both throw the same error as before.

If I look at the database schema, the Pod table has a pod_admin_id field and the PodAdmin table has a pod_id field.

I inherited this schema and I am just wondering if the original developer set this up correctly. Surely I should be able to update the relationship from either direction - isn't that the point of creating has_one and belongs_to, so you can have bi-directional relationships like this?


I found the problem, which is that I had added this line to PodAdmin table instead of the Pod table:

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

Apologies - but as you can see, what I am trying to achieve here is to prevent a Pod from having 2 PodAdmins. This validates does not seem to achieve that.

I can do this:

p = Pod.find(5)
pa_last = PodAdmin.last
pa_first = PodAdmin.first
pa_last = p
pa_first = p

and now both pa's have the same pod_id. How can I prevent that from happening?


After much reading and testing and with thanks to both @Anand and @Spickerman the problem was that the previous developer put a foreign key into both tables (the
and the
). Only the belongs_to table should have a foreign key. Also, the relationship had been defined the wrong way round. However, fixing this does not guarantee a robust solution. I highly recommend others with similar issues read this.


Instead of p.pod_admin = PodAdmin.last, call PodAdmin.last.pod = p - as others have mentioned, the pod_id is in the PodAdmin table, and not the other way around.


Based on update to question, the problem is because you have foreign key references both ways - you should either have pod_id in pod_admins table or pod_admin_id in pods table, but not both. Remove one of them with a new migration, and try again

> bundle exec rails g migration RemovePodIdFromPodAdmins

# db/migrations/XXXX_remove_pod_admin_id_from_pods
def change
  remove_column :pods, :pod_admin_id

bundle exec rake db:migrate

Then, as suggested above, call

pa = PodAdmin.last
pa.pod = p