ActiveModel::MissingAttributeError: can't write unknown attribute `ad_id' with FactoryGirl
Asked Answered
F

6

53

I have the following models:

class Ad < ActiveRecord::Base
  belongs_to :page

  has_one :image
  has_one :logo
end

class Page < ActiveRecord::Base
  has_many :logos
  has_many :images
  has_many :ads
end

class Image < ActiveRecord::Base
  belongs_to :page
  has_many :ads
end

And I have defined the following Factories:

factory :page do
  url 'test.com'
end

factory :image do
  width 200
  height 200
  page
end

factory :ad do
  background 'rgb(255,0,0)'
  page
  image
end

When I try to do this:

ad = FactoryGirl.create(:ad) I get the following error ActiveModel::MissingAttributeError: can't write unknown attribute ad_id' right in the line where I decide the image association in the ad Factory.

What am I doing wrong here?

Floorage answered 30/11, 2013 at 2:8 Comment(1)
Mauricio, it was only missing the attributes of the factories, but I was showing the associations. Anyways, I have added them.Floorage
C
62

When you say:

has_one :image

Rails expects you to define an ad_id field at the images table. Given the way your associations are organised, I assume you have an image_id and a logo_id a the ads table so instead of:

class Ad < ActiveRecord::Base
  belongs_to :page

  has_one :image
  has_one :logo
end

You probably mean:

class Ad < ActiveRecord::Base
  belongs_to :page
  belongs_to :image
  belongs_to :logo
end

If that's not the case then you need to add ad_id columns to both Image and Logo.

Callosity answered 30/11, 2013 at 2:43 Comment(7)
Oh that is interesting. I put 'has_one' because it sounded more natural to say an Ad HAS ONE Image.Floorage
has_one and has_many implies the foreign key is at the other end of the association, belongs_to that it is at the current object.Doubletongued
@MaurícioLinhares is a foreign key required in the case of through associations with either belongs_to or has_one/has_many?Biltong
No, through associations use the foreign key that is already declared at your object. It's just a shortcut.Doubletongued
belongs_to, has_one and has_many are not very descriptive of the underlying database schema IMO. references and referenced_by_one and referenced_by_many would be much harder to misunderstand.Noami
To those that come here and say, "This is similar to my error, but I'm sure my database schema is correct". You might be like me, and you're looking at development, not test. Make sure that the field got migrated in test. (Maybe something like: RAILS_ENV=test bundle exec rake db:migrate, but your mileage may vary.)Chevrette
I've read a nice mnemonic somewhere on SO that I can't find again. It's the Toy Story method to remember the keywords. Andy has_one Woody, Woody belongs_to Andy. Where is the foreign key? On Woody's foot!Carafe
S
6

If you are getting this error while running the specs, it may be the newly added field that are not migrated in the test environment. So migrate it in the test environment with the below command

rake db:migrate db:test:prepare
Shakira answered 31/12, 2020 at 12:27 Comment(0)
M
3

I ran into this same error and it took a while to figure out a fix. Just in case this helps someone else in the future, here's my scenario and what worked for me. Class names have been changed as this is for work:

I had 2 namespaced models:

Pantry::Jar
has_many :snacks, class_name: Pantry::Snack
accepts_nested_attributes_for :snacks

Pantry::Snack
belongs_to :pantry_jar, class_name: Pantry::Jar

When I would create a new jar with new snacks, I would get:

ActiveModel::MissingAttributeError: can't write unknown attribute `jar_id'

The fix was to change the has_many to be more explicit about the foreign key:

has_many :snacks, class_name: Pantry::Snack, foreign_key: :pantry_jar_id
Makepeace answered 21/3, 2019 at 15:0 Comment(0)
P
3

Check your test database.

In my case, sometimes I did not modify the columns in the test database after modifying the development database after an incorrect migration.

Pesticide answered 8/12, 2020 at 3:21 Comment(0)
C
2

If you're getting the error while testing and you're using different repositories accessing the same test database, check if the migrations are equal among projects.

If you reset the database each time you're running the tests, only migrations available in that repository will be run, hence triggering the error related to the missing foreign key

ActiveModel::MissingAttributeError: can't write unknown attribute ad_id'

You should have the migration file with something like:

class AddAdReferenceToImage < ActiveRecord::Migration[5.0]
  def change
    add_reference :images, :ad, foreign_key: true
  end
end

Candra answered 10/11, 2021 at 3:53 Comment(0)
W
0

In my case this message appeared because I tried setting a reference (with a column name different from the class name) like this:

Entity.create(reference: some_obj).save!

Although I'm not sure what exactly caused the issue, I was able to fix it by using the column name instead of the reference name:

Entity.create(reference_id: some_obj.id).save!
Wellchosen answered 20/5, 2022 at 17:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.