简体   繁体   中英

rails/rspec: Fabricator - testing associations (ActiveModel::MissingAttributeError)

I am writing tests for my models and came across an error I can't seem to resolve. I'm using rspec and Fabricator. Things work fine when being tested in isolation but when I try to test for associations I get an ActiveModel::MissingAttributeError.

models/user.rb

class User < ApplicationRecord
  ...
  validates :email, uniqueness: true, presence: true
  belongs_to :company, required: false
end

models/company.rb

class Company < ApplicationRecord
  validates :organisation_number, uniqueness: true, presence: true
  has_many :users, dependent: :destroy
end

schema

create_table "companies", force: :cascade do |t|
  t.string "organisation_number"
  ...
end

create_table "users", id: :serial, force: :cascade do |t|
    t.string "email", default: "", null: false
    ...
    t.bigint "company_id"
    t.index ["company_id"], name: "index_users_on_company_id"
    ...
  end

fabricators/user_fabricator.rb

Fabricator :user do
  email { Faker::Internet.email }
  password '123456'
  confirmed_at Time.now
end

fabricators/company_fabricator.rb

Fabricator :company do
  organisation_number { Faker::Company.swedish_organisation_number }
end

spec/user_spec.rb (first test passes, the second fails)

describe User do
  context '#create' do
    it 'Creates a user when correct email and password provided' do
      user = Fabricate(:user)
      expect(user).to be_valid
    end
    it 'Lets assign a company to user' do
      company = Fabricate(:company)
      expect(Fabricate.build :user, company: company).to be_valid
    end
  end
end

I also tried adding a company straight to the User fabricator, like so (which seems to me like a correct implementation of the documentation ):

Fabricator :user do
  email { Faker::Internet.email }
  password '123456'
  confirmed_at Time.now
  company
end

and the other way around, adding users to the Company fabricator, like so:

Fabricator :company do
  organisation_number { Faker::Company.swedish_organisation_number }
  users(count: 3) { Fabricate(:user) }
end

but both approaches left me with the same error:

User#create Lets assign a company to user Failure/Error: company = Fabricate(:company)
ActiveModel::MissingAttributeError: can't write unknown attribute 'company_id'

Any suggestions on what I'm doing wrong?

I would write up my own answer but I am not sure that I could describe it better than RSpec already has so this is taken directly from Here :

Rails 4.x ActiveRecord::Migration pending migration checks

If you are not using ActiveRecord you do not need to worry about these settings.

Users of Rails 4.x can now take advantage of improved schema migration and sync abilities. Prior to RSpec 3, users were required to manually run migrations in both the development and test environments. Additionally, the behavior differed depending on if the specs were run via rake or via the standalone rspec command.

With the release of Rails 4, new APIs have been exposed on ActiveRecord::Migration . This allows RSpec to take advantage of these new standard migration checks, mirroring behavior across the board.

  • Rails 4.0.x

    Add the following to the top of the rails_helper file after Rails has been required:

      ActiveRecord::Migration.check_pending! 

    This will raise an exception if there are any pending schema changes. Users will still be required to manually keep the development and test environments in sync.

  • Rails 4.1+

    With this release there was an exciting new feature. Users no longer need to keep the development and test environments in sync. To take advantage of this add the following to the top of the rails_helper file after Rails has been required:

      ActiveRecord::Migration.maintain_test_schema! 

    What this does is that rather than just raising when the test schema has pending migrations, Rails will try to load the schema. An exception will now only be raised if there are pending migrations afterwards the schema has been loaded.

    There are a few caveates to be aware of when using this:

    • Migrations still need to be run manually; although now this only has to be done in the 'development' environment

    • An exception will be raised If the schema has not been initialized. The exception will provide instructions stating rake db:migrate needs to be run.

It is possible to opt-out of checking for pending migrations. Since this is actually a feature of Rails, the change needs to be done as part of the Rails configuration. To do this, add the following to your config/environments/test.rb file:

 config.active_record.maintain_test_schema = false 

New RSpec projects don't need to worry about these commands as the rails generate rspec:install will add them automatically.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM