calling specific url in Rspec in integration test - ruby-on-rails-3

I'm trying to do the following in rspec (know that I shouldn't have hardcoded value) in an integration test:
get '/api/get-other-items?id=5109'
The closest I could find was: call a specific url with rspec but it selects only a single item. I have tried the following:
get :controller => 'api', :action => 'get-other-items', :id => '5109'
get 'api/get-other-items', :id => '5109'
These are giving me a bad argument(expected URI object or URI string)
If I run as
get get_other_items, :id => '5109' q
I get
undefined local variable or method `get_other_items' for #<RSpec::Core::ExampleGroup::Nested_1:0x007f938fd65590>
but the route does exist:
Mon Jan 23$ rake routes | grep get_other_items
get_other_items /api/get-other-items(.:format) {:controller=>"api", :action=>"get_other_items"}
How would I perform this simple get?
thx
update for answer 1 comment
here's the rspec code in question:
it "testing getting other items for menu item" do
get get_other_items_path(:id => '5109')
JSON.parse(response.body)
puts response.body
Mon Jan 23$ rspec requests/get_other_items_spec.rb
F
Failures:
1) GetOtherItems testing getting other items for menu item
Failure/Error: JSON.parse(response.body)
JSON::ParserError:
743: unexpected token at 'this is not found '
# ./requests/get_other_items_spec.rb:19:in `block (2 levels) in <top (required)>'
Finished in 13.57 seconds
1 example, 1 failure
Failed examples:

The call should be get get_other_items_path(:id => 5109) - you need to add path to the name of the route, or url if you want the full URL instead of a relative path.

Your route doesn't look like it's taking a :id as a parameter, if you want to send an :id I would expect to see the following:
get_other_items /api/get-other-items/:id(.:format) {:controller=>"api", :action=>"get_other_items"}
Given the structure of your generated route I assume that you are using match to define the route (There is no HTTP verb in your route). To fix it try:
match 'api/get-other-items/:id' => 'api#get_other_items'
If instead you are using restful routes then it looks like you have specified a collection route rather than a member route. A collection route doesn't take an :id and is designed to return many records of the type you have specified. To make it a member route use the following:
resources :api do
get 'get_other_items', :on => :member
end
Once you get this working you should be able to try the following in rspec in your ApiController spec:
get :get_other_items, :id => '5109'
If neither of these options work please post your routes entry so we can try something else.

Related

Routing error rails 3

I have a Rails 2.3.5 app with many controllers, models etc. which I'm trying to upgrade to Rails 3.2.21. I'm having some troubles with my routes. I tried to follow the Rails 3 new routing format but it doesn't seem to work. I'm getting two problems (which I guess all indicate one fundamental issue with my routing):
In the root ('/') I'm getting the generic "Welcome abroad" Rails
page. My routes (see below) have defined routing for root.
For some controllers I get No route matches [GET] "/study" message. My route shows this route, but for some reason doesn't define the GET method.
Here's my config/routes.rb code:
Myapp::Application.routes.draw do
root :to => 'study#index'
match 'login' => 'login', :protocol => 'https://'
resources :study_maps do
get :clone, :on => :member
end
# Route report create actions to the report controller
match 'report/create', :as => 'report'
match ':controller(/:action(/:id))(.:format)'
end
If I'm running rake routes I'm getting:
root / study#index
login /login(.:format) login#login {:protocol=>"https://"}
clone_study_map GET /study_maps/:id/clone(.:format) study_maps#clone
study_maps GET /study_maps(.:format) study_maps#index
POST /study_maps(.:format) study_maps#create
new_study_map GET /study_maps/new(.:format) study_maps#new
edit_study_map GET /study_maps/:id/edit(.:format) study_maps#edit
study_map GET /study_maps/:id(.:format) study_maps#show
PUT /study_maps/:id(.:format) study_maps#update
DELETE /study_maps/:id(.:format) study_maps#destroy
report /report/create(.:format) report#create
/:controller(/:action(/:id))(.:format) :controller#:action
Here's my StudyController#index code:
require 'myapp/studymgr'
require 'project_user'
require_dependency 'myapp/controller_extensions/report_manager'
class StudyController < ApplicationController
include PaginatorController
before_filter(:authenticate, :except => [:todo])
before_filter(:authorize,
:only => [:update, :destroy, :edit, :prune, :select_experiments ])
def index
#tags = Stag.find(:all).collect { |stag| stag.tag }
...
#include_ext = true
end
end
Can someone advise on what I'm missing?
Finally found a solution - my views had .rhtml extension. I found that this format is no longer supported under Rails 3 (What is the difference Between .erb , .rhtml and .html.erb?), so I changed all views extensions to .html.erb and then the routes worked with no need to specify explicit resource for each controller, just using the generic route: match ':controller(/:action(/:id))'.
As for the issue in the root route (#1 above), where I always got the Rails "Welcome abroad" page, despite having explicit route in my routes.rb, turns out I had to remove public/index.html which is loaded for root by Rails, and then my view was loaded.

Cloudmailin gets 500 from Heroku when delivering e-mails

I'm using the Cloudmailin addon to receive e-mail from my Heroku app. However, Cloudmailin has not been able to deliver - or, rather, it gets 500 from Heroku every time (so the address is correct).
The error in Heroku logs is
Started POST "/incoming_mails" for 109.107.35.53 at 2013-02-27 08:54:22 +0000
2013-02-27T08:54:23+00:00 app[web.1]: Entering the controller! Controlling the e-mail!
2013-02-27T08:54:23+00:00 app[web.1]:
2013-02-27T08:54:23+00:00 app[web.1]: NoMethodError (undefined method `[]' for nil:NilClass):
2013-02-27T08:54:23+00:00 app[web.1]: app/controllers/incoming_mails_controller.rb:7:in `create'
My routing is correct; the "Entering the controller! Controlling the e-mail!" comes from the puts at the beginning of the class, so the class definitely gets entered.
# routes.rb
post '/incoming_mails' => 'incoming_mails#create'
The file itself looks like this:
# /app/controllers/incoming_mails_controller.rb
class IncomingMailsController < ApplicationController
skip_before_filter :verify_authenticity_token
def create
puts "Entering the controller! Controlling the e-mail!"
Rails.logger.info params[:headers][:subject]
Rails.logger.info params[:plain]
Rails.logger.info params[:html]
if User.all.map(&:email).include? params[:envelope][:from] # check if user is registered
#thought = Thought.new
#thought.body = params[:plain].split("\n").first
#thought.user = User.where(:email => params[:envelope][:from])
#thought.date = DateTime.now
if #thought.save
render :text => 'Success', :status => 200
else
render :text => 'Internal failure', :status => 501
end
else
render :text => 'Unknown user', :status => 404 # 404 would reject the mail
end
end
end
User and Thought are database resources used elsewhere without a problem. The saving procedure is the same that works in scaffolding-generated Thought controller. The params and Rails.logger logic I copied from a Cloudmailin Rails 3 example.
I'm really confused - where am I going wrong? I'd really appreciate any pointers.
It turns out, this is why you shouldn't code while sleep-deprived. The problem was simple: there is no such thing as params[:envelope][:from], there is only params[:from]). My assumption that :from would be a sub-element of :envelope was probably formed by looking at the pattern in the second "Cloudmailin in Rails on Heroku" example, where a code used to log subject is Rails.logger.log params[:envelope][:subject].
I realized this was the error after reading the API documentation for 'original' Cloudmailin format. It was exceptionally silly of me not to have found / looked for this resource in the first place.
After fixing this, the code still didn't work, because User.where(:email => params[:from]) only returned a Relation object, while User object was expected. The error in Heroku logs was the following:
ActiveRecord::AssociationTypeMismatch (User(#29025160) expected,
got ActiveRecord::Relation(#12334440)):
Since there can only be one user with some e-mail, the fix User.where(:email => params[:from]).first has no side-effects and results in correct behavior.

Rspec test :create method for a nested resource

I'm trying to set up specs to properly run with my nested resource.
This is the test code I'm trying to properly set up
it "redirects to the created unit" do
post :create, {:course_id => #course.id , :unit => valid_attributes}
response.should redirect_to(course_unit_path(#course, Unit.last))
end
That essentially should try to create a nested resource "unit" for "course".
Unfortunatly I'm getting the following error on all POST DELETE and PUT tests
Failure/Error: post :create, {:course_id => #course.id , :unit => valid_attributes}
NoMethodError:
undefined method `unit_url' for #<UnitsController:0x000000059f1000>
That makes sense since unit_url should be course_unit_url but it's RSpec calling it...
How can I make RSpec select the right named path?
For all GET tests I passed the :course_id by hand.
This is what I did:
it "redirects to the created unit" do
unit_id = "barry"
Unit.any_instance.should_receive(:save).and_return(true)
Unit.any_instance.stub(:id).and_return(unit_id)
post :create, {:course_id => #course.to_param , :unit => valid_attributes}
response.should redirect_to(course_unit_path(#course, unit_id))
end
I decided that the point of this test was not that it created a new model and redirected it, but simply that it redirects. I have another spec to ensure it creates a new model. Another benefit to this approach is that it doesn't touch the database so it should run a little faster.
I hope that helps.
Edit:
I also just noticed I have this in my before :each section which may be relevant:
Course.stub!(:find).and_return(#course)
Edit again:
In this case, there was code in the controller which was doing the offending call. As per comment below.

Rails 3: Defining two paths with different parameters for an action in a controller

I have a controller named users and index action in it. By default I have the path
get '/users' => 'users#index', :as => 'users'
Now I want to create one more path with a different parameter being passed
get '/users/:city' => 'users#index', :as => 'list_users'
But this gives as error, No route matches {:controller=>"users"}.
I ran rake routes and found the path I defined to be present over there but it doesn't works.
What shall be done to make this work.

RoutingError with RSpec Controller test on Scoped Route

So I have a route that looks like this:
scope "4" do
scope "public" do
scope ":apikey" do
resources :shops
end
end
end
And a bunch of controller specs, an example of which looks like this:
describe ShopsController do
describe "when responding to a GET" do
context "#new" do
it "should create a new instance of the shop class" do
get :new
#shop.should_not_be_nil
end
end
end
end
In rake routes, as well as via a web browser, this controller/action works fine. However, RSpec throws:
1) ShopsController when responding to a GET#new should create a new instance of the shop class
Failure/Error: get :new
ActionController::RoutingError:
No route matches {:controller=>"shops", :action=>"new"}
# ./spec/controllers/shops_controller_spec.rb:9:in `block (4 levels) in <top (required)>'
When I remove the scope statements from the route, the tests work fine. Is there a way to "inform" RSpec of the route scopes?
Thanks in advance!
According to your routes, :apikey is a required parameter, so you need to add it to your get:
get :new, :apikey => "something"
Also you should change the expectation in your next line to this:
assigns[:shop].should_not be_nil
Use assigns to check the controller's instance variables, and separate should_not from the matcher with a space, not an underscore. That last bit takes some getting used to.