expected ActiveRecord::RecordNotFound but nothing was raised - ruby-on-rails-3

How to get the test pass for this error?
Rspec result
**2) Api::V1::UsersController GET #show - a user it fails showing a user
Failure/Error:
expect do
get 'show', params: { id: 2 }
end.to raise_error(ActiveRecord::RecordNotFound)
expected ActiveRecord::RecordNotFound but nothing was raised
# ./spec/controllers/users_controller_spec.rb:100:in `block (3 levels) in <main>'
**
Controller -method
def show
begin
user = User.find(params[:id])
render json: UserSerializer.new(user).serialized_json
rescue ActiveRecord::RecordNotFound => e
render json: { error: e.to_s }, status: :not_found
end
end
**
Rspec controller
it 'it fails showing a user' do
expect do
get 'show', params: { id: 2 }
end.to raise_error(ActiveRecord::RecordNotFound)
end

I could solve it in this way,
def show
user = User.find(params[:id])
begin
render json: UserSerializer.new(user).serialized_json
rescue ActiveRecord::RecordNotFound => e
render json: { error: e.to_s }, status: :not_found
end
end

Related

undefined method `each' for nil:NilClass (ActiveMerchant)

After filling payment information, when I click on 'place order' I get this error
NoMethodError in OrdersController#create
undefined method `each' for nil:NilClass
OrdersController
def create
#order = Order.new(order_params)
#order.add_line_items_from_cart(#cart)
credit_card = ActiveMerchant::Billing::CreditCard.new(params[:credit_card])
respond_to do |format|
if #order.save
Cart.destroy(session[:cart_id])
session[:cart_id] = nil
format.html { redirect_to category_url(Category.first), notice: 'Thank you for your order.' }
format.json { render :show, status: :created, location: #order }
else
format.html { render :new }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
order model:
attr_accessor :card_no, :card_cvv, :expiry_date
I'm guessing i need to group :card_no, :card_cvv and :expiry_date in a data structure labelled 'credit_card' but I don't know how. Thanks!
Edit:
NoMethodError (undefined method `each' for nil:NilClass):
app/controllers/orders_controller.rb:32:in `new'
app/controllers/orders_controller.rb:32:in `create'
Rendering C:/RailsInstaller/Ruby2.2.0/lib/ruby/........
You need to get the params according to what you're sending from your form, so, if you want to access to them, you must take the params from the order root, that's to say, the card_no will be params[:order][:card_no], and this way all of them.
And in order to make use of the ActiveMerchant gem and to create a new "CreditCard", you need to pass there your values received from the form, something like:
credit_card = ActiveMerchant::Billing::CreditCard.new(
:first_name => params[:order][:first_name],
:last_name => params[:order][:last_name],
:number => params[:order][:card_cvv],
:month => params[:order][:month],
:year => Time.now.year+1, # documentation value
:verification_value => '000' # documentation value
)

(Rspec) expected #count to have changed by 1, but was changed by 0

I started to learn Rspec one day ago. When writing test for my articles controller, I got error at create new article. Here is my controller:
def create
Article.transaction do
begin
#article = Article.new(article_params)
respond_to do |format|
if #article.save
view_context.create_sitemap
flash[:show_alert] = true
format.html { redirect_to edit_admin_article_path(#article), notice: 'Created sucessfull' }
else
format.html { render :new }
format.json { render json: #article.errors,notice: "Unprocessable entity" }#may need a helper to handle exception
end
end
rescue Exception => e
raise ActiveRecord::Rollback
respond_to do |format|
flash[:show_alert] = true
format.html { redirect_to new_admin_article_path, notice: 'Create failed'}
end
end
end
end
here is my test:
describe "POST #create" do
context "with valid attributes" do
it "creates a new article" do
expect{
post :create, params: { article: FactoryGirl.attributes_for(:article) }
}.to change(Article, :count).by(1)
end
it "redirects to the index page" do
post :create, params: { article: FactoryGirl.attributes_for(:article) }
expect(response).to redirect_to admin_articles_path
end
end
context "with invalid attributes" do
it "does not save the new article" do
expect{
post :create, params: { article: FactoryGirl.attributes_for(:article) }
}.to_not change(Article, :count).by(1)
end
it "re-renders the :new template" do
post :create, params: { article: FactoryGirl.attributes_for(:article) }
expect(response).to render_template :new
end
end
end
And here is the log:
3) Admin::ArticlesController POST #create with valid attributes creates a new article
Failure/Error:
expect{
post :create, params: { article: FactoryGirl.attributes_for(:article) }
}.to change(Article, :count).by(1)
expected #count to have changed by 1, but was changed by 0
# ./spec/controllers/admin/articles_controller_spec.rb:29:in `block (4 levels) in <top (required)>'
I spent time to search for the same issue but, all of them didn't solve my error. My problem is I cannot find out where the error come from. Any help is appreciated.

how to test rails custom validation

I have a custom validation that checks whether a param is valid JSON or not:
def is_valid_json
begin
!!JSON.parse(preferences)
rescue
errors.add(:preferences, "This is not valid JSON")
end
end
In my controller test, I want to make sure that when I send in a bad value, the status code of the response is 422. Here is the spec from my controller:
it 'should return a 422 when validations fail' do
put :update, {:user_preferences => { :email => #email, :preferences => 'badval' } }
expect(response.status).to eq(422)
res = JSON.parse(response.body)
expect(res['error']).to_not be_blank
end
The test fails due to an error:
Failure/Error: put :update, {:user_preferences => { :email => #email, :preferences => 'badval' } }
ActiveRecord::RecordInvalid:
Validation failed: Preferences This is not valid JSON
Controller code:
def update
#user_preference = UserPreference.where(email: params[:user_preferences][:email]).first
authorize! :update, #user_preference
#user_preference.update_attributes!(params[:user_preferences])
render_api_response(#user_preference)
end
When I make the request from the browser, I get a 422 return status code, so is there a reason that I can't get the same result from the test?
The way I see it, update_attributes raises an exception, and you need to catch that. Perhaps you are doing an XHR call with your browser and you code handles that exception code (422) in the front end. For tests to work you should rescue the exception and respond with the relevant status in your render
rescue ActiveRecord::RecordInvalid do
render json: {
error: "Invalid params",
status: 422
},
status: 422
end

Rails: nested resources and routing errors

I've got a Template model, and a Doc model. They're nested resources, with the Templates being the parent, thus:
resources :templates do
get "/documents/lock/:id" => "docs#lock", :as => :lock_doc
get "/documents/unlock/:id" => "docs#unlock", :as => :unlock_doc
get "/documents/pdf/:id" => "docs#pdf", :as => :pdf_doc
resources :docs, :path => :documents
end
That part, I think, all works fine. When I try to submit the form for creating a doc the record exists but I get routing errors, thus:
ActionController::RoutingError (No route matches {:action=>"edit", :controller=>"docs", :template_id=>nil, :id=>#<Doc id: 2, user_id: "admin", cover: "1209hpnl", message: "The world economic outlook is improving, albeit slo...", created_at: "2013-01-07 03:54:05", updated_at: "2013-01-07 03:54:05", issue_code: "1209hpnl", title: "January 2013", locked: nil, retired: "active", template: nil>}):
app/controllers/docs_controller.rb:134:in `block (2 levels) in create'
app/controllers/docs_controller.rb:132:in `create'
The lines correspond to the create method:
def create
#doc = Doc.new(params[:doc])
respond_to do |format|
if #doc.save
format.html { redirect_to share_url(#doc), notice: "Saved. You may from here #{view_context.link_to('edit', edit_template_doc_url(#doc))} it further, #{view_context.link_to('finalise', template_lock_doc_url(#doc))} it, or return #{view_context.link_to('home', root_url)}.".html_safe }
format.json { render json: #doc, status: :created, location: #doc }
else
format.html { render action: "new" }
format.json { render json: #doc.errors, status: :unprocessable_entity }
end
end
end
I think the problem lies somewhere in here, but I can't for the life of me figure it out.
Cheers for any help!
EDIT: with rake routes
template_lock_doc GET /templates/:template_id/documents/lock/:id(.:format) docs#lock
template_unlock_doc GET /templates/:template_id/documents/unlock/:id(.:format) docs#unlock
template_pdf_doc GET /templates/:template_id/documents/pdf/:id(.:format) docs#pdf
template_docs GET /templates/:template_id/documents(.:format) docs#index
POST /templates/:template_id/documents(.:format) docs#create
new_template_doc GET /templates/:template_id/documents/new(.:format) docs#new
edit_template_doc GET /templates/:template_id/documents/:id/edit(.:format) docs#edit
template_doc GET /templates/:template_id/documents/:id(.:format) docs#show
PUT /templates/:template_id/documents/:id(.:format) docs#update
DELETE /templates/:template_id/documents/:id(.:format) docs#destroy
templates GET /templates(.:format) templates#index
POST /templates(.:format) templates#create
new_template GET /templates/new(.:format) templates#new
edit_template GET /templates/:id/edit(.:format) templates#edit
template GET /templates/:id(.:format) templates#show
PUT /templates/:id(.:format) templates#update
DELETE /templates/:id(.:format) templates#destroy
The problem is in your call to edit_template_doc_url(#doc) inside the notice string. You need to supply the template as well, like this:
edit_template_doc_url(params[:template_id], #doc)

How do I pass a params parameter into an rspec controller test?

I have the following rspec test:
def valid_attributes
{ "product_id" => "1" }
end
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, {:line_item => valid_attributes}, valid_session #my valid_session is blank
}.to change(LineItem, :count).by(1)
end
Which fails with this error:
1) LineItemsController POST create with valid params redirects to the created line_item
Failure/Error: post :create, {:line_item => valid_attributes}, valid_session
ActiveRecord::RecordNotFound:
Couldn't find Product without an ID
# ./app/controllers/line_items_controller.rb:44:in `create'
# ./spec/controllers/line_items_controller_spec.rb:87:in `block (4 levels) in <top (required)>'
This is my controller's create action:
def create
#cart = current_cart
product = Product.find(params[:product_id])
#line_item = #cart.line_items.build(:product => product)
respond_to do |format|
if #line_item.save
format.html { redirect_to #line_item.cart, notice: 'Line item was successfully created.' }
format.json { render json: #line_item.cart, status: :created, location: #line_item }
else
format.html { render action: "new" }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
As you can see, my action expects a product_id from the request's params object. How should I work this product_id into my rspec test?
I've tried placing this before statement:
before(:each) do
ApplicationController.any_instance.stub(:product).and_return(#product = mock('product'))
end
. . . but it changes nothing. I am missing some rspec concept here somewhere.
Try like this:
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, :product_id => 1
}.to change(LineItem, :count).by(1)
end
Hope it helps.
I ended up resolving my issue by using a fixture instead of attempting to mock the solution as suggested in another answer.
The reason for this is that the controller does the query to get information from the database: product = Product.find(params[:product_id]) and I found a fixture-based solution was quicker to resolve my problem than one using a mock and I could not figure out how to stub the query quickly (the fixtures also help with another test on the controller so it eventually helped anyway.
For reference:
I referenced my fixture with this line toward the top of the test: fixtures :products
I changed my test to:
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, :product_id => products(:one).id
}.to change(LineItem, :count).by(1)
end
And here is my fixture file, products.yml:
one:
name: FirstProduct
price: 1.23
two:
name: SecondProduct
price: 4.56