Short Version
I have added a company model to my rails app which is in the devise user registration view using accepts_nested_attributes on the user model. The setup works when I run through it manually but when I execute the test it fails with:
Failure/Error: click_button 'Sign up'
NoMethodError:
undefined method `owner_id=' for #<Company:0x007fe2411e17b8>
How can I fix this error? I am not sure what it is telling me.
The test code which is in spec/features:
authentication_flows_spec.rb
it "signs me up" do
visit new_user_registration_path
fill_in 'user[email]', with: @new_user[:email]
fill_in 'user[password]', with: @new_user[:password]
fill_in 'user[password_confirmation]', with: @new_user[:password]
fill_in 'user[company_attributes][name]', with: @new_user[:company_name]
click_button 'Sign up'
expect(current_path).to eq(dashboard_path)
end
Long Version
Recently I have added a Company model to my app which has two relationships. One to say it has_many users and one to say it belongs_to an owner (which is a existing user).
Company Model
class Company < ActiveRecord::Base
belongs_to :owner, class_name: 'User', foreign_key: 'owner_id'
has_many :users
end
The company is created in the devise user registration by telling my user model to accepts_nested_attributes_for the company.
User Model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :company
accepts_nested_attributes_for :company
end
Devise User Registration View
.section.first.dark-grey.p-b-20
.container
.grid
.col-md-6.col-md-offset-3
%h2.grid-title Sign up
= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
= devise_error_messages!
.form-row
= f.email_field :email, autofocus: true, class: "form-control", placeholder: "email address"
.form-row
= f.password_field :password, autocomplete: "off", class: "form-control", placeholder: "password"
.form-row
= f.password_field :password_confirmation, autocomplete: "off", class: "form-control", placeholder: "confirm password"
= f.fields_for :company_attributes do |ff|
.form-row
= ff.text_field :name, class: "form-control", placeholder: "company name"
.form-row
= f.submit "Sign up", class: "btn btn-primary btn-cons"
= render "devise/shared/links"
Finally I override the devise user registrations controller to add the logic to set the owner of the company
Overriden Devise Registrations Controller
class RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
#GET /users/sign_up
def new
# Override Devise default behaviour and create a company as well
build_resource({})
resource.build_company
respond_with self.resource
end
#POST /users/sign_up
def create
# Let devise create user and company using nested attributes
super
# Set the owner of the newly created company as new user
company = resource.company
company.owner_id = resource.id
company_saved = company.save
if company_saved == false
resource.destroy
company.destroy
return new_user_registration_path
end
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u|
u.permit(:email, :password, :password_confirmation, :company_attributes => :name)
}
end
end
On your Reddit post, adding attr_accessor :owner_id
seemed to resolve the problem. That suggests that the test db schema really is the problem as @HermanHiddema suggests. Instead of db:test:prepare (removed in 4.1), you could do RAILS_ENV=test rake db:schema:load
or similar to drop the existing schema and recreate from scratch.
maintain_test_schema! appears to only load the schema if you the schema version is different from the one in the DB. So if you modified migrations that had already run (as one example), it wouldn't detect that the test schema needs to be reset.