Rails testing: "No route matches" for custom route - ruby-on-rails

I have following route:
GET /confirm/:token(.:format) Confirmations#confirm
Controller:
class ConfirmationsController < ApplicationController
# GET /confirm/<token>
def confirm
#user = User.find_by_email_token(params[:token])
if #user
#user.confirmed = true
#user.email_token = nil
#user.save!
sign_in #user
redirect_to root_url, flash: { success: "Welcome <#{#user.email}>, your address has been verified." }
elsif
redirect_to root_url, flash: { error: "Error: could not find matching user record." }
end
end
end
And this simple confirmations_controller_spec.rb:
require 'spec_helper'
describe ConfirmationsController do
let(:user) { FactoryGirl.create(:user, email_token: "some_token") }
describe "Get confirm" do
it "confirms user with valid email_token" do
get :confirm, token: "some_token"
assigns(:user).should eq(user)
user.reload.email_token.should be_nil
end
it "does not confirm user with invalid email_token"
end
end
but it fails:
1) ConfirmationsController Get confirm confirms user with valid email_token
Failure/Error: get :confirm, token: "some_token"
ActionController::RoutingError:
No route matches {:token=>"some_token", :controller=>"confirmations", :action=>"confirm"}
# ./spec/controllers/confirmations_controller_spec.rb:9:in `block (3 levels) in <top (required)>'
Anyone see what (could be multiple things) I screwed up?
BTW- I'm using a get request here (as opposed to put) because it's being initiated from a text based email so we can't, to my understanding, use a put request...

In your rake routes, Confirmations should not have a capital letter.
Can you define the route like so in config/routes.rb:
match '/confirm/:token' => 'confirmations#confirm'

Related

RSpec controller test errors within embedded resource

I was writing tests for my app using responders gem.
Here are my routes:
resources :sites do
resources :pages, shallow: true
end
My PagesController chunk of code:
def create
respond_with(#page = #site.pages.create(page_params))
end
def find_site
#site = current_user.sites.find(params[:site_id])
end
And tests that are failing:
sign_in_user
let(:user_2) { create(:user) }
let(:site) { create(:site, user: #user) }
let(:page) { create(:page, site: site, user: #user) }
describe 'POST #create' do
context 'with valid attributes' do
it 'associates new page with the site' do
expect { post :create, params: { page: attributes_for(:page), site_id: site } }.to change(site.pages, :count).by(1)
end
it 'redirects to show view' do
post :create, params: { page: attributes_for(:page), site_id: site }
expect(response).to redirect_to page_path(assigns(:page))
end
end
Errors are following:
1) PagesController POST #create with valid attributes associates new page with the site
Failure/Error: expect { post :create, params: { page: attributes_for(:page), site_id: site } }.to change(site.pages, :count).by(1)
expected #count to have changed by 1, but was changed by 0
# ./spec/controllers/pages_controller_spec.rb:37:in `block (4 levels) in <top (required)>'
2) PagesController POST #create with valid attributes redirects to show view
Failure/Error: expect(response).to redirect_to page_path(assigns(:page))
ActionController::UrlGenerationError:
No route matches {:action=>"show", :controller=>"pages", :id=>nil}, missing required keys: [:id]
# ./spec/controllers/pages_controller_spec.rb:42:in `block (4 levels) in <top (required)>'
If I change site.pages in first test to Page - it's actually working.
So I am really confused how to fix this tests and where is the mistake.
Solved
Problem was with my PagesController, method create should look like this
def create
#page = #site.pages.build(page_params)
#page.user = current_user
#page.save
respond_with(#page)
end
Problem was with my PagesController, method create should look like this
def create
#page = #site.pages.build(page_params)
#page.user = current_user
#page.save
respond_with(#page)
end

Devise RSpec Error

I am trying to validate that the current_user's organization matches that of the organization they are trying to view.
Here's the part of the controller that's failing this test (#organization is being defined in an earlier method):
if current_user.organization != #organization
redirect_to root_path, notice: "Not authorized to edit this organization"
end
Here's the failing test:
require 'rails_helper'
RSpec.describe Admin::PagesController, :type => :controller do
describe 'GET #home' do
login_user
before do
#organization = FactoryGirl.create(:organization)
end
context "valid params" do
it "renders the home template and returns http 200" do
get :home, name: #organization.name
expect(response).to render_template("home")
expect(response.status).to eq(200)
end
end
end
Here's my factory:
factory :user do
email { Faker::Internet.email }
organization_id 1
password "foobarfoobar"
password_confirmation { |u| u.password }
end
...And here's where login_user is being defined:
module ControllerMacros
def login_user
#request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user)
sign_in user
end
end
Stacktrace:
1) Admin::PagesController GET #home valid params renders the home template and returns http 200
Failure/Error: it "renders the home template and returns http 200" do
expecting <"home"> but rendering with <[]>
# ./spec/controllers/admin/pages_controller_spec.rb:15:in `block (4 levels) in <top (required)>'
However:
[2] pry(#<RSpec::ExampleGroups::AdminPagesController::GETHome::ValidParams>)> subject.current_user.organization == #organization
=> true
Not sure what is going wrong here, seems like pretty standard stuff. Any ideas?
Turns out the issue was that I was sending in the wrong parameter - should have been sending #organization.subdomain, not #organization.name. :(

Unable to test the session[:user_id] value set in POST #create in SessionsController spec with RSpec/Rails

I'm struggling with how to correctly test the POST #create action in the SessionsController. I've attempted to stub authentication. My assumption is that a valid test should test that the session[:user_id] is in fact equal to the #user.id value, after the post :create action is executed. However, I get nil returned for session[:user_id].
Mocks, stubs, etc are still a bit new to me. The stub for authentication seems pretty straightforward. However, why can't I get the session value to be returned when I run this test?
The test for valid authentication is currently failing (though it works in actual practice - i.e. I can sign in to the app). This is the one I'm concerned with. The second test (invalid password) is passing, and seems fine. All of my other session controller specs are passing.
Here's the portion of my sessions_controller_spec.rb file that deals with the session creation via POST #create:
require 'rails_helper'
describe SessionsController, type: :controller do
describe "POST #create" do
context "where authentication is valid" do
it "creates a new session with a welcome message" do
#user = create(User, id: 1)
allow(#user).to receive(:authenticate).and_return #user
post :create, email: "test#example.com", password: "secret1234"
expect(session[:user_id]).to eq #user.id
expect(flash[:notice]).to match("Welcome back!")
end
end
context "where password is invalid" do
it "re-renders the signin page with an alert message" do
user = create(:user)
post :create, session: { email: user.email, password: 'invalid' }
expect(response).to render_template :new
expect(flash[:alert]).to match("Incorrect email/password combination!")
end
end
end
# CODE FOR OTHER TESTS OMITTED
end
This is my sessions_controller.rb file:
class SessionsController < ApplicationController
def new
end
def create
if user = User.authenticate(params[:email], params[:password])
session[:user_id] = user.id
flash[:notice] = "Welcome back!"
redirect_to root_path
else
flash.now[:alert] = "Incorrect email/password combination!"
render :new
end
end
def destroy
session[:user_id] = nil
redirect_to new_session_path, notice: "Signed Out!"
end
end
The test returns the following error:
1) SessionsController POST #create where authentication is valid creates a new session with a welcome message
Failure/Error: expect(session[:user_id]).to eq #user.id
expected: 1
got: nil
(compared using ==)
# ./spec/controllers/sessions_controller_spec.rb:12:in `block (4 levels) in <top (required)>'
# ./spec/rails_helper.rb:42:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:41:in `block (2 levels) in <top (required)>'
Is there a better, or preferred, way to test that the SessionsController successfully creates the session and sets the session[:user_id] value?
Comments, code critiques, etc, are welcome.
You didn't stub the method correctly:
allow(#user).to receive(:authenticate).and_return #user
In the controller you are calling authenticate on a class, not the instance. The line above should be:
allow(User).to receive(:authenticate).and_return #user

Count; find User with id= Minitest

I am following Michael Hartl's Ruby on Rails tutorial and I am not sure why I am getting this Error when according to the tutorial everything should pass:
1) Error:
UsersControllerTest#test_should_get_show:
ActiveRecord::RecordNotFound: Couldn't find User with 'id'=
app/controllers/users_controller.rb:7:in `show'
test/controllers/users_controller_test.rb:10:in `block in <class:UsersControllerTest>'
My minitest:
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
# add invalid information and test that the User.count never changes
# also test that the sign up path is visited after invalid sign up
test "invalid signup information" do
# visit the signup path using get
get signup_path
assert_no_difference "User.count" do
post users_path, user: { name: "", email: "user#invalid", password: "foo", password_confirmation: "bar"}
end
assert_template "users/new"
end
end
I compared my users_controller to the official github tutorial and it looks the same
Users controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
# strong parameters
#user = User.new(user_params)
if #user.save
# handle save
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
I dont really understand why id is being searched for as well. My database is empty with no users. I am currently testing that inputing invalid parameters for sign up will not add another user.
my UserControllerTest:
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
test "should get new" do
get :new
assert_response :success
end
test "should get show" do
get :show
assert_response :success
end
end
Show renders a page for specific user, so you need to pass it the id param. Change the test to:
test "should get show" do
user = User.create
get :show, id: user.id
assert_response :success
end
FYI, A small breakdown of the error message:
1) Error:
Error
UsersControllerTest#test_should_get_show:
In test test_should_get_show in class UserControllerTest
ActiveRecord::RecordNotFound: Couldn't find User with 'id'=
Database doesn't contain User object with empty id
app/controllers/users_controller.rb:7:in `show'
File and line that directly caused the error
test/controllers/users_controller_test.rb:10:in `block in <class:UsersControllerTest>'
File and line where the action originated from.

Pre-processing within a Rails Controller create method does not work

I am following Michael Hartl's tutorial, and trying to implement the reply twitter-like functionality, ie. "#122-john-smith: hello there" should be a reply to user 122.
I first tried filtering the "#XXX-AAA-AAA" part using a before_filter, but I decided to try it first in the very same Micropost#create action. So far I've got this MicropostController:
class MicropostsController < ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
before_filter :correct_user, only: [:destroy]
#before_filter :reply_to_user, only: [:create]
def index
end
def create
#micropost=current_user.microposts.build(params[:micropost])
#Rails.logger.info "hoooola"
regex=/\A#(\d)+(\w|\-|\.)+/i
message=#micropost.content.dup
isResponse=message.match(regex)[0].match(/\d+/)[0]
#micropost.response=isResponse
if #micropost.save
flash[:success]="Micropost created!"
redirect_to root_path
else
#feed_items=[]
render 'static_pages/home'
end
end
def destroy
#micropost.destroy
redirect_to root_path
end
private
def correct_user
#micropost = current_user.microposts.find_by_id(params[:id])
redirect_to root_path if #micropost.nil?
end
def reply_to_user
regex=/\A#(\d)+(\w|\-|\.)+/i
#I use [0] cause the output of match is a MatchData class with lots of bs
mtch=params[:micropost][:content].match(regex)[0]
#puts mtch
##micropost=current_user.microposts.build(params[:micropost])
if mtch != nil
user_id=mtch.match(/\d+/)[0]
#replied_user=User.find(user_id)
#micropost.response=user_id unless #replied_user.nil?
end
end
end
And this is the snippet test I'm trying to pass:
require 'spec_helper'
describe "MicropostPages" do
subject { page }
let(:user) { FactoryGirl.create(:user) }
before { valid_signin user }
describe "micropost creation" do
before { visit root_path }
describe "with invalid information" do
it "should not create a micropost" do
expect { click_button "Post" }.should_not change(Micropost,
:count)
end
describe "error messages" do
before { click_button "Post" }
it { should have_content('error') }
end
end
describe "with valid information" do
before { fill_in 'micropost_content', with: "Lorem ipsum" }
it "should create a micropost" do
expect { click_button "Post" }.should change(Micropost,
:count).by(1)
end
end
end
...
end
If I run these tests I get the follwing error:
Failures:
1) MicropostPages micropost creation with invalid information should not create a micropost
Failure/Error: expect { click_button "Post" }.should_not change(Micropost, :count)
NoMethodError:
undefined method `[]' for nil:NilClass
# ./app/controllers/microposts_controller.rb:14:in `create'
# (eval):2:in `click_button'
# ./spec/requests/micropost_pages_spec.rb:11:in `block (5 levels) in <top (required)>'
# ./spec/requests/micropost_pages_spec.rb:11:in `block (4 levels) in <top (required)>'
2) MicropostPages micropost creation with invalid information error messages
Failure/Error: before { click_button "Post" }
NoMethodError:
undefined method `[]' for nil:NilClass
# ./app/controllers/microposts_controller.rb:14:in `create'
# (eval):2:in `click_button'
# ./spec/requests/micropost_pages_spec.rb:14:in `block (5 levels) in <top (required)>'
However if I modify the tests and comment out all the #XXX filtering in the Micropost#create action:
def create
#micropost=current_user.microposts.build(params[:micropost])
#Rails.logger.info "hoooola"
#regex=/\A#(\d)+(\w|\-|\.)+/i
#message=#micropost.content.dup
#isResponse=message.match(regex)[0].match(/\d+/)[0]
##micropost.response=isResponse
if #micropost.save
flash[:success]="Micropost created!"
redirect_to root_path
else
#feed_items=[]
render 'static_pages/home'
end
end
The tests pass just fine and the new Micropost is not a Nil object.
It can't seem to find an explanation here.
The error comes from this line:
isResponse=message.match(regex)[0].match(/\d+/)[0]
Check if your two match calls actually match correctly. If the pattern is not found in your string, nil is returned and the [0] call is made on nil. There's two instances in this line alone where this could happen.
Try to spread it out over several lines and check the return values of your matches or extend your Regex to properly check the pattern in one go.

Resources