Zoinks10
Zoinks10

Reputation: 629

Unknown attribute errors thrown by Rspec when trying to test a nested attribute

I have built an application based on the Hartl course - up to and including section 9.2 (authentication). From there I have tried to extend the functionality by adding in an Organization model. Initially I tried using the scaffold generate command line function, decided it had built too much, rolled it back and then built it by hand. I believe in this mess I may have screwed up my migrations (see below). I'm using Rails v4.1.1, Rspec 3.0.0 and Capybara 2.2.0 - all databases are postgres.

An Organization can have_many users, whereas each User belongs_to only one Organization.

I should note that using the dev environment on my own machine, I have the field for Organization working correctly during a user sign up - it creates a new user, I can view both organization and user pages correctly, and there are no errors thrown in the performance of the app. My issues begin when I'm testing using the Rspec tests - throwing a range of errors like this:

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

My models:

class Organization < ActiveRecord::Base
  validates :organization_name, presence: true, length: { maximum: 50 }
  has_many :users
end

class User < ActiveRecord::Base
  belongs_to :organization
  accepts_nested_attributes_for :organization
  before_save { self.email = email.downcase }
  before_create :create_remember_token, :create_organization
  validates :name, presence: true, length: {maximum: 50}
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(?:\.[a-z\d\-]+)*\.[a-z]+\z/i
  validates :email, presence: true, format: {with: VALID_EMAIL_REGEX}, uniqueness: {case_sensitive: false}
  has_secure_password
  validates :password, length: {minimum: 6}

  def create_organization
    self.organization = Organization.create(:organization_name => Organization.organization_name) unless self.organization.present?
  end

My Factories:

FactoryGirl.define do
  factory :organization do
    organization_name "Orgname"
  end
  factory :user do
    association :organization
    name "A Name"
    email "[email protected]"
    password "foobar"
    password_confirmation "foobar"
  end
end

An example Rspec test suite:

describe "edit" do
  let(:organization) { FactoryGirl.create(:organization) }
  let(:login) { FactoryGirl.create(:login,
                                   :organization => organization,
                                   :user => FactoryGirl.create(:user)) }
  before do
    sign_in login
    visit edit_user_path (user)
  end

My schema.rb file:

ActiveRecord::Schema.define(version: 20140619041326) do

  create_table "organizations", force: true do |t|
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string "organization_name"
  end

  create_table "users", force: true do |t|
    t.string "name"
    t.string "email"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string "password_digest"
    t.integer "organization_id"
    t.string "remember_token"
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
  add_index "users", ["organization_id"], name: "index_users_on_organization_id", using: :btree
  add_index "users", ["remember_token"], name: "index_users_on_remember_token", using: :btree

end

It may be worth noting here that when I first started running the tests I was using the Rspec version recommended in Hartl's book - meaning I had to force through changes from the development DB to the test DB using the bin/rake dg:migrate RAILS_ENV=test command line function. Every time I ran this, my schema.rb file (as posted above) would lose the line

t.integer "organization_id"

and I'd have to rake the db to get it working again.

I realise there's a lot of info here, and that my questions are probably pretty dumb (I'm new to the language and framework and this is my first app) but it's driving me mad. I've spent the past week trying to find out why the tests are broken when the actual app itself is working.

Any help would be much appreciated.

Upvotes: 2

Views: 1480

Answers (2)

SteveTurczyn
SteveTurczyn

Reputation: 36860

I think there's no factory for :login ... and I think that the sign_in method wants to pass in a user object.

So change your let(:login) statement to...

let(:login) { FactoryGirl.create(:user, :organization => organization) }

Upvotes: 0

SteveTurczyn
SteveTurczyn

Reputation: 36860

Your before_create method create_organization the following line...

  self.organization = Organization.create(:organization_name => Organization.organization_name) unless self.organization.present?

You're referencing a class (not object) method when you do Organization.organization_name and no such class method exists.

You could create it in the Organization model... it could be some default value...

def self.organization_name
  "Default Organization Name"
end

Upvotes: 0

Related Questions