Reputation: 6278
I'm just throwing this out there because I really can't figure this out. When I call for instance user.articles.create! { title: 'blah' }
nil is returned but the object is created. I've not seen anything like this before and was wondering if someone else has?
I've tried rails 3.2.13 and 3.2.12 and they both do the same thing.
EDIT
In active record both create and create! ends up IN THIS METHOD that is supposed to return the record or throw an exception.
def create_record(attributes, options, raise = false, &block)
unless owner.persisted?
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
end
if attributes.is_a?(Array)
attributes.collect { |attr| create_record(attr, options, raise, &block) }
else
transaction do
add_to_target(build_record(attributes, options)) do |record|
yield(record) if block_given?
insert_record(record, true, raise)
end
end
end
end
Upvotes: 3
Views: 1623
Reputation: 6237
I had the same symptom, and this question is the only relevant hit that I could find. I'll throw my solution into the mix in case it helps anyone else.
The code worked in real life, and only failed under rspec
. All the troubleshooting I did made no sense, pointing to create!
being broken, which I never believed.
As it turns out, I was mocking create!
so it never got called. Adding .and_call_original
to my mock solved the problem.
My model was something like this: (not really...but compatible with this answer)
class Flight < ApplicationRecord
has_many :seats
def create_seats(seat_count)
seat_count.times { Seat.create!(flight: self) }
seats.each(&:raise_seatback_and_lock_tray)
end
And my test was:
it 'creates enough empty seats' do
expect(Seat).to receive(:create!).twice
flight.create_seats(2)
end
The expectation was met (confirmed manually), but an error was raised:
NoMethodError:
undefined method `raise_seatback_and_lock_tray=' for nil:NilClass
Changing my mock to allow create!
to actually be called solved the problem:
it 'creates enough empty seats' do
expect(Seat).to receive(:create!).twice.and_call_original
flight.create_seats(2)
end
This now passed:
creates enough empty seats
1 example, 0 failures
Upvotes: 2
Reputation: 2254
If I'm not mistaken Factory Girl mimic the actual object you're dealing with through your predefined factory. Therefor User#articles
might not return what you think it is when called on a factory.
Changing
user.articles.create! { title: 'blah' }
to
create(:article, user: user, title: 'blah')
should enforce the association through Factory Girl's interface.
Upvotes: 2
Reputation: 10769
I believe there is something going on with your attr_accessible
or attr_accessor
in your Article
class. I you might have not included the user_id
or something else...
There is also a similar question here: rails Model.create(:attr=>"value") returns model with uninitialized fields
Upvotes: 1
Reputation: 7616
If you are expecting the object to be returned use
user.articles.create { title: 'blah' }
Why some methods have bang (!), you can read this topic Why are exclamation marks used in Ruby methods?
Upvotes: -1