ActionController::RoutingError: No route matches error while unit testing - ruby-on-rails

I found a lot of questions with same title but could not found the appropriate answer.
I am testing a controller
Player Controller
def create
player = Player.create(params[':player'])
if player.valid?
# if creation successful, log the player in:
player_session = PlayerSession.create(
player: player,
session_token: ActiveSupport::SecureRandom.urlsafe_base64
)
render json: {session_token: player_session.session_token}
else
render json: {error: "Player name already exists."}, status: :unprocessable_entity
end
end
Player Controller Test
test "create" do
post(:create,
{
'player' => {
'player_name' => "usman",
'password' => 123,
'email' => 'ranasaani#gmail.com'
}
}
)
assert_select response.body
end
while executing the test file the following errors display on console.
ActionController::RoutingError: No route matches {:player=>{"player_name"=>"usman", "password"=>123, "email"=>"ranasaani#gmail.com"}, :controller=>"pl
ayers", :action=>"create"}
D:/jruby-1.7.1/lib/ruby/gems/shared/gems/actionpack-3.0.3/lib/action_dispatch/routing/route_set.rb:424:in `raise_routing_error'
D:/jruby-1.7.1/lib/ruby/gems/shared/gems/actionpack-3.0.3/lib/action_dispatch/routing/route_set.rb:406:in `generate'
D:/jruby-1.7.1/lib/ruby/gems/shared/gems/actionpack-3.0.3/lib/action_dispatch/routing/route_set.rb:453:in `generate'
D:/jruby-1.7.1/lib/ruby/gems/shared/gems/actionpack-3.0.3/lib/action_dispatch/routing/route_set.rb:449:in `generate_extras'
D:/jruby-1.7.1/lib/ruby/gems/shared/gems/actionpack-3.0.3/lib/action_dispatch/routing/route_set.rb:445:in `extra_keys'
D:/jruby-1.7.1/lib/ruby/gems/shared/gems/actionpack-3.0.3/lib/action_controller/test_case.rb:143:in `assign_parameters'
D:/jruby-1.7.1/lib/ruby/gems/shared/gems/actionpack-3.0.3/lib/action_controller/test_case.rb:402:in `process'
D:/jruby-1.7.1/lib/ruby/gems/shared/gems/actionpack-3.0.3/lib/action_controller/test_case.rb:47:in `process'
D:/jruby-1.7.1/lib/ruby/gems/shared/gems/actionpack-3.0.3/lib/action_controller/test_case.rb:355:in `post'
D:/Projects/lyricle/test/functional/players_controller_test.rb:5:in `test_create'
org/jruby/RubyBasicObject.java:1659:in `__send__'
why this error is here?

You have to define routes if you want anything to be able to access your controller.
So, in your config/routes.rb :
App::Application.routes.draw do
resources :your_resource_plural_name
end

The create action should be like this:
def create
#player = Player.new(params[:player])
#your code
end
also you need to add new action before create action:
def new
#player = Player.new
end
in routes.rb you should have resources :players
#player is an instance variable to make you able to call it in the view also.
See Rails Guide to create your first application.
Also check Rails for Zombies they are very good

Related

Rails4 Rspec Controller Tests No route matches

All. I am a beginner developer of Ruby on Rails. There is an error that I have been struggling and not been able to solve.
I am trying to see if an variable #chat_group declared in messages_controller.rb matches another variable declared in message_controller_spec.rb. I have not had any clue to solve this error because I am 100% positive that I am giving what I am supposed to give to as a parameter, which is chat_group_id as the route says.
Does anyone have any insight to solve this problem?
Or has anyone encountered a similar issue before?
If you does or has, could you please give a way of solving this problem?
Any advice would be appreciated! Thanks in advnace!
1) MessagesController#GET index when the user logs in Checking if the variable in index action matches
Failure/Error: get :index, params: index_params
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"messages", :params=>{:chat_group_id=>"522"}}
# ./spec/controllers/messages_controller_spec.rb:13:in `block (4 levels) in <top (required)>'
messages_controller_spec.rb
RSpec.describe MessagesController, type: :controller do
let(:chat_group) { create(:chat_group) }
let(:message) { create(:message) }
let(:index_params) { { chat_group_id: chat_group } }
describe '#GET index' do
context 'when the user logs in' do
login_user
it 'Checking if the variable in index action matches' do
get :index, params: index_params
expect(assigns(:chat_group)).to eq chat_group
end
end
end
end
Route.rb
chat_group_messages GET /chat_groups/:chat_group_id/messages(.:format) messages#index
POST /chat_groups/:chat_group_id/messages(.:format) messages#create
chat_groups GET /chat_groups(.:format) chat_groups#index
POST /chat_groups(.:format) chat_groups#create
new_chat_group GET /chat_groups/new(.:format) chat_groups#new
edit_chat_group GET /chat_groups/:id/edit(.:format) chat_groups#edit
chat_group PATCH /chat_groups/:id(.:format) chat_groups#update
PUT /chat_groups/:id(.:format) chat_groups#update
MessageController.rb
class MessagesController < ApplicationController
before_action :set_chat_group
def index
#chat_groups = current_user.chat_groups
#messages = #chat_group.messages
#message = Message.new
respond_to do |format|
format.html { render :index }
format.json { render json:
#chat_group.messages.includes(:user).map{|x| x.json_api} }
end
end
private
def set_chat_group
#chat_group = ChatGroup.find(params[:chat_group_id])
end
end
Update
I solved the error! I put the way of solving it in the comments below!
I am so sorry. I was looking at a documentation for Rails5 instead of Rails4.
It says that I should pass the chat_group_id by writing like below.
Rails4
before do
get :index, { chat_group_id: chat_group }
end
Not Like this
before do
get :index, params: { chat_group_id: chat_group }
end
This error made me realize how important it is to read the documentation...
For those who put comments and tried to do so, THANK YOU VERY MUCH!
try to change type: controller to type: request?
Also you can use, request type and specify path:
get chat_group_messages_path(chat_group.id), index_params
Cheers
I think You are doing everything right.
but this line : expect(assigns(:group)).to eq group
you expected assigns(:group) but i can't see any variable named group in your index action that you are testing.
also you are expecting that to equal group "eq group", but in your let blocks in the example above no variable named group exists.
So try to do expect(assigns(:chat_groups)).to eq chat_group
the assigns(:chat_groups) uses the same name of the instance variable inside your action, and the eq chat_group uses the name of the variable in the let block

Why does my test try to render a different & invalid route?

I have a test that tries to view a subscription that doesn't exist. I run this test with a bunch of users from my fixtures. In the case of the user in the admin role when the app gets to the point of trying to render the response it has changed the action from :show to :edit and dropped the id param. Yet when I try and use byebug to trace the execution I never seem to be able to pinpoint when it happens.
my test is:
test "#{u.role} can not view subscriptions that don't exist" do
self.send('sign_in_' + u.role)
get :show, id:1234567890
assert_redirected_to root_path
assert_includes flash[:alert], "That subscription doesn't exist"
end
where u is a user loaded from my fixtures.
The error I get is:
SubscriptionsControllerTest#test_admin_can_not_view_subscriptions_that_don't_exist:
ActionView::Template::Error: No route matches {:action=>"edit", :controller=>"subscriptions", :id=>nil} missing required keys: [:id]
app/views/subscriptions/show.html.erb:13:in `_app_views_subscriptions_show_html_erb__1518678276755260966_70268849069860'
test/controllers/subscriptions_controller_test.rb:58:in `block (2 levels) in <class:SubscriptionsControllerTest>'
my controller looks like this:
class SubscriptionsController < ApplicationController
load_and_authorize_resource except: [:create,:new]
before_action :set_subscription
def show
end
def edit
end
...
private
def subscription_params
params.require(:subscription).permit(:email,:confirmed)
end
def set_subscription
#byebug if user_signed_in? && current_user.role == 'admin' && self.action_name == 'show'
begin
if (params.has_key? :id) && (controller_name == 'subscriptions')
#subscription = Subscription.find(params[:id])
elsif user_signed_in?
#subscription = current_user.subscription || Subscription.new(email: current_user.email)
else
#subscription = Subscription.new
end
rescue ActiveRecord::RecordNotFound
#subscription = Subscription.new
flash.alert = "That subscription doesn't exist"
end
end
end
load_and_authorize_resource comes from cancancan.
my routes related to this test are:
resources :subscriptions do
member do
get 'confirm'
end
end
I don't really know where to go from here, so any advice would be appreciated.
Take a look at the stack trace for this exception:
SubscriptionsControllerTest#test_admin_can_not_view_subscriptions_that_don't_exist:
ActionView::Template::Error: No route matches {:action=>"edit", :controller=>"subscriptions", :id=>nil} missing required keys: [:id]
app/views/subscriptions/show.html.erb:13:in `_app_views_subscriptions_show_html_erb__1518678276755260966_70268849069860'
test/controllers/subscriptions_controller_test.rb:58:in `block (2 levels) in <class:SubscriptionsControllerTest>'
app/views/subscriptions/show.html.erb, line 13. Are you calling link_to (or a similar helper method) with a nil ID, maybe?
Look at your error message. It says the id parameter is missing. It is possible you are giving it a nil value. Because of this the router can't route the request properly.
Also, the error is for an request to the edit action, but the code you are showing is calling the show action. Can you clean up the code examples and error messages shown and make them consistent?

RSpec - Request for not existing record has response with status 200

After adding decent_exposure the following spec is failed:
it "redirects to root_path if product cannot be found" do
product = create :product
get :show, {id: 2}
expect(response).to redirect_to(root_path)
end
I use CanCanCan and add the following code to ApplicationController, so it rescues when the record couldn't be found and redirects to root path:
rescue_from ActiveRecord::RecordNotFound do
redirect_to root_path, alert: controller_name.singularize.capitalize << " cannot be found"
end
And it do works, it redirects if a record doesn't exist and I see 'Completed 302 Found' message in console. But spec fails with the message 'Expected response to be a redirect, but was <200>'. Seems to be it's due to 'Rendered products/show.html.haml within layouts/application' before 'Redirected to http://localhost:3000/' which appears after adding decent_exposure.
In controller I have only:
expose(:product, attributes: :product_params)
expose(:products) { Product.paginate(page: params[:page], per_page: 5) }
without Show action.
Thank you for any help!
Added Show action:
def show
return unless product
end
Now it works correctly.

Rails Api Rspec Test that takes params on route

routes.rb
get 'students/name_starts_with/:letter', to: 'students#name_starts_with'
get 'students/with_last_name/:last', to: 'students#with_last_name'
students_controller.rb
def name_starts_with
#students = Student.all.select{|s| s.first_name.start_with?(params[:letter]}
render json: #students.to_json
end
def with_last_name
#students = Student.all.select{|s| s.last_name == params[:last]}
render json: #students.to_json
end
students_controller_spec.rb
context '#name_starts_with' do
let!(:first_student){Student.create(first_name: 'John', last_name: 'Doe'}
it "starts with #{first_student.first_name.split('').first}" do
get :name_starts_with
expect(response.status).to eq(200)
expect(first_student.first_name.split('').first).to be('J')
end
end
context '#with_last_name' do
let!(:first_student){Student.create(first_name: 'John', last_name: 'Doe'}
it "has last name #{first_student.last_name}" do
get :with_last_name
expect(response.status).to eq(200)
expect(first_student.last_name).to be('Doe')
end
end
I have seeded bunch of student names. As far as I know both of these should be get routes/get requests. I am getting same error for both:-
Failure/Error: get :name_starts_with
ActionController::UrlGenerationError:
No route matches {:action=>"name_starts_with", :controller=>"students"}
# ./spec/controllers/students_controller_spec.rb:45:in `block (3 levels) in <top (required)>'
Should they be POST routes instead. Am I missing something. Am I doing whole thing wrong. Can somebody please help me solve this issue please.
I think this is route matching error. parameter letter is missing in this call.
Replace
get :name_starts_with
with
get :name_starts_with, letter: first_student.first_name.split('').first
I think this will fix your error.
I know this sounds stupid, but is your StudentsController inheriting from ApplicationController? (ApplicationController inherits from ActionController::Base
...and I'm not sure if you need the #students.to_json if you already declared render :json in your controller. just put render json: #students

Rspec fails on "<ActiveRecord>.nil? or <ActiveRecord>.field.empty?" while app works

Starting my journey on TDD with Rspec and having some issues.
Can't understand why my rspec fails on if ... OR condition.
def director
#movie = Movie.find_by_id(params[:id])
if #movie.nil? or #movie.director.empty?
flash[:notice] = "The movie has no director info"
redirect_to movies_path
else
# success
end
end
Rspec test:
before ... #stubs
it 'assigns movies array in director action' do
Movie.stub(:find_by_id).and_return(#movie)
get "director", :id => 1
...
end
Error:
1) MoviesController assigns movies array in director action
Failure/Error: get "director", :id => 1
NoMethodError:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.empty?
If record is not found, then #movie.nil? should satisfy the condition and #movie.director.empty? shouldn't evaluated against; is that correct?
In this case I don't care if there's no such record or the director field of requested record is blank, I treat it the same way.
Appreciate your help.
UPDATE
I've removed some controller stuff into model like this:
controller:
def director
#movies = Movie.same_director_by_id(params[:id])
if #movies.blank?
redirect_to movies_path
end
end
movie:
def self.same_director_by_id (id)
movie = self.find_by_id(id)
if movie.nil? or movie.director.blank?
return []
else
return self.where("id != ?", id).find_all_by_director(movie.director)
end
end
rspec:
it 'assigns movies array in director action' do
Movie.should_receive(:same_director_by_id).and_return([#movie])
get "director", :id => 1
assigns(:movies).should be_kind_of(Array)
end
Now all controller specs pass beautifully.
I'll test model separately.
UPDATE 2:
The issue was that I stubbed :director on a Model, not on a mock!
apneadiving was correct.
As discussed in comments, it's mandatory to mock/stub every object/method. directory was missing here.

Resources