Rspec method create error - ruby-on-rails

i try to test method create in my controller:
def create
#fund = Fund.new({started_at: Date.strptime(params[:fund].delete(:started_at), '%m/%d/%Y')}.merge(fund_params))
if #fund.save
flash[:alert] = "Fund #{#fund.name} saved!"
redirect_to funds_path
else
flash[:error] = "Fund #{#fund.name} could not be saved"
render :edit
end
end
file spec:
it 'Can create a new fund' do
fund = FactoryGirl.create(:fund)
post :create
expect(response).to redirect_to(funds_path)
end
And show this error:
NoMethodError: undefined method `delete' for nil:NilClass
The error is in this line, for the method 'delete':
#fund = Fund.new({started_at: Date.strptime(params[:fund].delete(:started_at),...
i don't know how solve this problem, Thanks.

As the error message says, that's because params[:fund] is nil. Try to send the proper parameters to the create action:
post :create, fund: { add_here_needed_params_for_this_action }
Example:
post :create, fund: { started_at: Date.today }

Related

How to test destroy failure in ruby-on-rails

everyone.
I'm gonna test an active record object destroy failure but I've problems creating a failure situation.
I have a before_filter method called 'require_user_payment_info' which validates the #payment_info object before the delete method is called, so I can't create a 'bad' #payment_info object before the delete method is called.
Here's the require_user_payment_info method:
def require_user_payment_info
#payment_info = credit_card_model.slave.find_by_user_guid(user_guid)
if !#payment_info || #payment_info.user_guid != user_guid
redirect_to(:controller => 'store', :action => 'index') and return false
else
if((#payment_info.card_expires_year.to_i < Date.today.year) ||
((#payment_info.card_expires_month.to_i < Date.today.month) && (#payment_info.card_expires_year.to_i == Date.today.year)))
#payment_info.card_account_public = "" #clear this out so the user is forced to re-enter the credit card number
#payment_info.valid?
flash.now[:error] = t('ui_flash_errors.card_expired_error')
end
end
end
And the actual delete method:
def delete
# required to be called via a delete request
redirect_to :action => 'edit' and return if !request.delete?
if #payment_info.destroy
flash[:notice] = "Delete SUCCESSFUL"
redirect_to :action => 'new'
else
flash[:error] = "Delete failed"
redirect_to :action => 'edit'
end
Any ideas?
This is my solution:
def test_delete
payment_info = Factory.create(:payment_info, :user_guid=>#user.guid, :card_expires_month=>'04',
:card_expires_year=>(Date.today.year+2).to_s, :cardholder_city=>"test city",
:cardholder_state=>'NC', :cardholder_country=>'US', :cardholder_zip=>'27612')
PaymentInfo.any_instance.stubs(:destroy).returns(false)
delete(:delete, {}, #session)
assert_response(:redirect)
assert_equal false, assigns(:payment_info).blank?
assert_redirected_to({:controller=>'account', :action=>'edit'})
assert_equal flash[:error], "There was an error deleting your credit card information. Please try again."
end

Rspec Create Post with nested parameters

I'm trying to fix some tests that I have written in my comments controller. As of now, with my current tests I get this error:
Failure/Error: #outlet = Outlet.find(params[:comment][:outlet_id])
ActiveRecord::RecordNotFound:
Couldn't find Outlet with 'id'=
Here is an example of some of the tests
describe '#create' do
context 'with valid attributes' do
before :each do
#outlet = FactoryGirl.create(:outlet)
#user = FactoryGirl.create(:user)
#comment_params = FactoryGirl.attributes_for(:comment)
end
let(:create) { post :create, params: { outlet_id: #outlet.id, user_id: #user.id, comment: #comment_params } }
it "creates new comment" do
expect { create }.to change { Comment.count }.by(1)
end
it "increases the post comment count by 1" do
expect { create }.to change { #outlet.comments.count }.by(1)
end
it "increases user comment count by 1" do
expect { create }.to change { #user.comments.count }.by(1)
end
end
end
I'm pretty sure this is happening because of my create statement in my tests
let(:create) { post :create, params: { outlet_id: #outlet.id, user_id: #user.id, comment: #comment_params } }
Here is my comments controller create action
def create
#outlet = Outlet.find(params[:comment][:outlet_id])
#comment = #outlet.comments.build(comment_params)
#comment.user_id = current_user.id
if #comment.save
redirect_to(#outlet)
end
end
I'm pretty sure it is not working, because the outlet_id that it is looking for is a nested parameter inside of the comments parameter. How would I fix my rspec test to have it look for a nested parameter?
Just pass your params as arguments to the post call, nesting as necessary, e.g.:
post :create, user_id: #user.id, comment: { outlet_id: #outlet.id }

Undefined method `errors'

I have this code in my update action of Registration controller. And I get undefined method 'errors'. I can not use flash message here for some reason.
if subjects_selected.blank?
#registration = Registration.where(:student_id => params[:registration][:student_id], :semester_id => params[:registration][:semester_id] )
redirect_to editreg_registrations_path(#registration.first.id, params[:registration][:student_id], params[:registration][:semester_id]), #registration.errors.add(:You_have_to_register_for_at_least_one_subject) and return
end
How can I access error method here?
you can take the method in Registration model for error displaying the errors
like
error_array = Registration.validate_subjects(params[:registration][:student_id],params[:registration][:semester_id])
then in Registration model
def validate_subjects(student_id, semester_id)
is_registration = self.where(:student_id=>student_id,:semester_id =>semester_id)
error_array=[]
if !is_registration
//RIGHT THE CODE
error_array << "You_have_to_register_for_at_least_one_subjec"
end
error_array
end
if subjects_selected.blank?
#registration = Registration.where(:student_id => params[:registration][:student_id], :semester_id => params[:registration][:semester_id] )
if !#registration.errors
redirect_to editreg_registrations_path(#registration.first.id, params[:registration][:student_id], params[:registration][:semester_id])
else
#registration.errors.add(:You_have_to_register_for_at_least_one_subject)
end
end

Why is my rspec test failing with ActionController::RoutingError:?

Basically I'm stumped as to why this particular test is failing. The page works fine when I go in and test it out by hand but the test keeps failing. First off, here's the error.
2) Setlist Pages Edit page adding a song
Failure/Error: click_button submit
ActionController::RoutingError:
No route matches {:action=>"edit", :controller=>"setlists", :id=>nil}
# ./app/controllers/allocations_controller.rb:15:in `create'
# (eval):2:in `click_button'
# ./spec/requests/setlist_pages_spec.rb:79:in `block (4 levels) in <top (required)>'
I realise that the id is set to nil but I know that when the test initially visits the page it renders because tests for content pass. I'm not sure why it points to the create controller when I'm testing the edit action as well? The test is shown below:
before do
#setlist = Setlist.create(date: Date.today, morning: true)
end
...
describe "Edit page" do
let(:admin) { FactoryGirl.create(:admin) }
let(:submit){ "Add Song" }
before do
#secondSong = FactoryGirl.create(:song)
sign_in admin
visit edit_setlist_path(#setlist)
end
it{ should have_content("Edit a Setlist")}
describe "adding a song" do
before do
select("#{#secondSong.title} by #{#secondSong.artist}", from: 'Songs')
click_button submit
end
it{ should have_selector('div.alert.alert-success')}
it "should create a new allocation" do
expect{click_button submit}.to change(Allocation, :count).by(1)
end
end # end adding a song
end # end edit test
Controller code as requested:
def create
#setlist = Setlist.new(params[:setlist])
if #setlist.save
#success!
flash[:success] = "Setlist saved"
##setlist.allocations.build produce invalid allocation with nil id
redirect_to setlist_path(#setlist)
else
#FAIL!
render 'new'
end
end
def edit
#songs= Song.search(params[:search])
##songs = Song.all(order: 'title')
#setlist = Setlist.find(params[:id])
#allocations = #setlist.allocations
#allocation = Allocation.new
#selections = Song.all.collect {|s| [ [s.title, s.artist].join(" by "), s.id ]}
end
def update
#setlist = Setlist.find(params[:id])
#selections = Song.all.collect {|s| [ [s.title, s.artist].join(" by "), s.id] }
#allocations = #setlist.allocations
#allocation = Allocation.new
#Allocation parameters
#allocation.song_id = params[:allocation][:song_id]
#allocation.setlist_id = #setlist.id
#allocation.songPosition = #setlist.songs.count + 1
if #setlist.update_attributes(params[:setlist])
if #allocation.save
flash[:success] = "SETLIST SAVED!"
redirect_to edit_setlist_path(#setlist)
else
flash[:fail] = "Sorry there was an error adding songs to the setlist"
render 'edit'
end
else
flash[:fail] = "Invalid Set"
render 'edit'
end
end
Any pointers would be much appreciated!

Why do I get this noMethodError error?

This is the error:
NoMethodError in VideosController#update
undefined method `each' for #<Topic:0x1032ee330>
This is the application trace:
app/models/video.rb:19:in `assign_topics'
app/controllers/videos_controller.rb:41:in `update'
app/controllers/videos_controller.rb:40:in `update'
this is my assign_topics method:
def assign_topics
if #topic_names
self.topics = Topic.find_or_create_by_name(#topic_names)
end
end
Note that I'm following this: http://media.railscasts.com/videos/167_more_on_virtual_attributes.mov
Here's the video controller's update method:
def update
#video = current_user.videos.find(params[:id])
respond_to do |format|
if #video.update_attributes(params[:video])
format.html { redirect_to(#video, :notice => 'Video was successfully updated.') }
else
format.html { render :action => "edit" }
end
end
end
I'd guess that your assign_topics method is at fault. Topic.find_or_create_by_name will return a single Topic instance, then you assign that to self.topics and self.topics is probably expecting an Array (or some other Enumerble); then later, the update process will try to loop through self.topics using each and you get your error.
You mention, in a comment, that you tried something like this:
self.topics = #topic_names.each { |n| Topic.find_or_create_by_name(n) }
But that won't work because each returns the original array and so the above is equivalent to this:
#topic_names.each { |n| Topic.find_or_create_by_name(n) }
self.topics = #topic_names
and all the Topic instances that you found/created are simply thrown away.
So, you might have better luck using collect like this:
def assign_topics
if #topic_names
self.topics = #topic_names.collect { |n| Topic.find_or_create_by_name(n) }
end
end
You are getting a NoMethodError Exception because somewhere in your code you are trying to loop, via .each(), on something that is not an array/enumerable.
According to your exception, you are calling .each() on a Model Object(Topic), which would make sense to not have the .each() method.

Resources