RSpec: Testing rescue_from - testing

How can I test rescue_from is RSpec? I'd like to make sure that if one of the exceptions is raised, that the controller correctly sets the flash and does the redirect. Is there a way to simulate the exception?
rescue_from PageAccessDenied do
flash[:alert] = "You do not have the necessary roles to access this page"
redirect_to root_url
end
rescue_from CanCan::AccessDenied do |exception|
flash[:alert] = exception.message
redirect_to root_url
end

Assuming that you have an authorize! method that raises the exception, you should be able to do something like this:
describe "rescue_from exceptions" do
it "rescues from PageAccessDenied" do
controller.stub(:authorize!) { raise PageAccessDenied }
get :index
response.should redirect_to("/")
flash[:alert].should == "You do not have the necessary roles to access this page"
end
end

Related

How do I emulate logging in for controller tests?

I have a SearchesController that requires a user to be logged in before it will do its thing.
I'd like to write an rspec helper function login to emulate logging in for controller tests. (NB: I will handle integration / requests specs separately.) My attempts so haven't worked: the logged_in? method in ApplicationController returns false.
The question: how do I write the 'login' helper?
Here's the RSpec controller test:
# file: spec/controllers/searches_controller_spec.rb
require 'spec_helper'
require 'controllers_helper'
describe SearchesController do
include ControllersHelper
describe "GET index" do
it 'without login renders login page' do
get :index
response.should redirect_to(login_path)
end
it 'with login finds searches belonging to user' do
me = FactoryGirl.create(:user)
my_searches = FactoryGirl.create_list(:search, 2, :user => me)
not_me = FactoryGirl.create(:user)
not_my_searches = FactoryGirl.create_list(:search, 2, :user => not_me)
login(me) # want to define this in spec/controllers_helper.rb
get :index
assigns(:searches).should =~ my_searches
end
end
end
Here's the Controller:
# file: app/controllers/searches_controller.rb
class SearchesController < ApplicationController
def index
unless logged_in?
redirect_to login_path, :alert => "You must be logged in to access this page."
else
#searches = Search.where(:user_id => current_user.id)
respond_to do |format|
format.html
format.json { render json: #searches }
end
end
end
end
And here's the ApplicationController code. Note that current_user = x has the effect of logging x in, and it's rather simple: it sets #current_user and session[:user_id].
# file: app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
force_ssl
protected
def current_user
#current_user ||= User.find_by_id(session[:user_id])
end
def current_user=(user)
#current_user = user
session[:user_id] = user && user.id
end
def logged_in?
!!#current_user
end
def require_login
unless logged_in?
redirect_to login_path, :alert => "You must be logged in to access this page."
end
end
helper_method :current_user, :logged_in?, :require_login
end
I may have said this before, but if Stack Overflow gave badges answering one's own questions, I'd have a LOT of badges! :)
Okay, to answer this question you need to look at the documentation for ActionController::TestCase. When you do so, you'll find that it sets up bindings for:
#controller
#request
#response
So for the specific controller given in the OP, writing the login method is trivial:
# file: spec/controllers_helper.rb
module ControllersHelper
def login(user)
#controller.send(:current_user=, user)
end
end
(Did I hear someone say RTFM again? I thought so...)

Rails use not condition with before_filter

I'm using before_filter in my application. I have a method logged_in? which returns true if the user is logged in.
def logged_in?
!!current_user
end
def current_user
#current_user = (User.find(session[:user_id]) if session[:user_id]) || false
end
Now in my users controller I want an action to execute only if a user is not logged in. For this I want to use the not condition with logged_in? method in before_filter as:
before_filter :!(logged_in?)
But this gives me an error. I'm resisting creating a new method for not logged in.
Please help me figure out the correct syntax to accomplish this.
While the accepted answer seems to work, I would have done it differently.
before_filter :login_required, unless: :logged_in?
def login_required
redirect_to login_path, notice: 'Please login'
end
This will execute the method login_required unless the user is already logged in. See http://robots.thoughtbot.com/post/159805303/before-filter-wisdom for more info.
You could pass a block to before_filter:
before_filter { |c| !c.logged_in? }
But this wouldn't really do anything, since the return value from the before filter isn't going anywhere. If you want to execute an action if a user is not logged in, then you should be putting that action into the before_filter.
For example, if the action was to redirect to the login page, path, you could do this:
before_filter { |c| redirect_to login_path unless c.logged_in? }
That's actually long enough to justify a method of its own:
before_filter :login_required
def login_required
redirect_to login_path unless logged_in?
end
application_controller.rb
before_filter :authorize
def current_user
#current_user ||= User.find_by(id: session[:user_id])
end
helper_method :current_user
protected
def authorize
unless User.find_by(id: session[:user_id])
redirect_to login_url, :notice => "Not Authorize Member"
end
end

Rails: Capture the URL that produced ActionController::RoutingError

I am trying to capture the URL that produced a routing error. My end goal is the change the domain on the URL to check if it exists on our old site (changed the domain) and if so redirect to the old site. Here is what I have do far.
unless Rails.application.config.consider_all_requests_local
rescue_from Exception, with: :render_500
rescue_from ActionController::RoutingError, with: :check_old_site
rescue_from ActionController::UnknownController, with: :render_404
rescue_from ActionController::UnknownAction, with: :render_404
rescue_from ActiveRecord::RecordNotFound, with: :render_404
end
private
def check_old_site(exception)
#Need to edit the URL but I need access to before I can write the code to modify
captured_and_modified_url = ???
case Net::HTTP.get_response(URI.parse(captured_and_modified_url))
when Net::HTTPSuccess then redirect_to captured_and_modified_url
else render_404(exception)
end
end
def render_404(exception)
#not_found_path = exception.message
respond_to do |format|
format.html { render template: 'errors/error_404', layout: 'layouts/application', status: 404 }
format.all { render nothing: true, status: 404 }
end
end
So for this question I just want to get at the URL that got to 404 error. Thanks for any help up front.
Figure this out a while ago. request.path
def check_old_site(exception)
exception_url = "http://old.richarddawkins.net#{request.path}"
case Net::HTTP.get_response(URI.parse(exception_url))
when Net::HTTPSuccess then redirect_to exception_url
else render_404(exception)
end
end

Why doesn't my current_user helper method work during tests?

I have a Rails 3.2.3 application and I am using MiniTest and Capybara to run my integration tests. I rolled my own authentication and created a current_user helper_method in my application_controller.rb.
My application layout file only displays certain links, like logout, etc., when a user is logged in.
But the current_user method does not work during tests. It looks like this:
class ApplicationController < ActionController::Base
protect_from_forgery
private
def authenticate
if current_user.blank?
redirect_to root_url, :alert => "You must first log in."
end
end
def authenticate_admin
unless current_user and current_user.admin?
redirect_to root_url, :alert => "You must be logged in as an administrator to access this feature."
end
end
def current_user
begin
#current_user ||= User.find(session[:user_id]) if session[:user_id]
rescue
nil
end
end
helper_method :current_user
end
So in my application.html.erb file there is:
<% unless current_user.blank? %>
<li><%= link_to logout_path %></li>
So this works when I test it through the browser, but not in my test. "current_user" ends up being nil.
I am new to BDD, but is there something that prevents sessions from being created during tests? What am I missing?
NOTE: helper methods defined in controllers are not included.
from here.
The solution is to organize them in a dedicated helper class.

Rspec2: response.should render_template("new") after invalid params fails

I am testing a controller in RSpec2 and for both my create and update actions, when passed invalid params, the controller should render either the "new" or "edit" templates respectively. It is doing that, but my test never passes.
describe "with invalid params" do
before(:each) do
User.stub(:new) { mock_user(:valid? => false, :save => false) }
end
it "re-renders the 'new' template" do
post :create, :company_id => mock_company.id
response.should render_template("new")
end
end
Results in this:
re-renders the 'new' template
expecting <"new"> but rendering with <"">
Here is the controller action:
respond_to do |format|
if #user.save
format.html {
flash[:notice] = "#{#user.full_name} was added to #{#company.name}."
redirect_to company_users_url(#company)
}
else
logger.debug #user.errors
format.html{
render :new
}
end
end
This problem also seems to be isolated to this controller. I have almost identical code running another controller and it is fine. I am not sure where the problem could be.
Update:
Here are the two mock methods
def mock_user(stubs={})
#mock_user ||= mock_model(User, stubs).as_null_object
end
def mock_company(stubs={})
(#mock_company ||= mock_model(Company).as_null_object).tap do |company|
company.stub(stubs) unless stubs.empty?
end
end
Turned out it was a problem with stubbing and CanCan. CanCan was loading the resources and uses some different methods than what I thought.