RSpec tests with devise: could not find valid mapping - ruby-on-rails-3

I'm trying to run controller specs with devise 1.3.4. (and factory girl)
I followed the instructions in the git wiki for the project. I am able to log in as a user using the login_user method created in the macro, but login_admin fails with the following error:
...
sign_in Factory.create(:admin)
Could not find a valid mapping for #<User id: 2023, email: "admin1#gmail.com", .... >
Factory:
Factory.define :user do |f|
f.sequence(:username) {|n| "user#{n}"}
f.sequence(:email) {|n| "user#{n}#gmail.com"}
f.email_confirmation {|fac| fac.email }
f.password "a12345Den123"
f.password_confirmation "a12345Den123"
# f.admin 0
end
Factory.define :admin, :class => User do |f|
f.sequence(:username) {|n| "admin#{n}"}
f.sequence(:email) {|n| "admin#{n}#gmail.com"}
f.email_confirmation {|fac| fac.email }
f.password "a12345Den123"
f.password_confirmation "a12345Den123"
f.admin 1
end
Controller macros module:
module ControllerMacros
def login_admin
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user] #it should map to user because admin is not a model of its own. It produces the same result either way.
#admin = Factory.create(:admin)
sign_in #admin
end
end
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
#user = Factory.create(:user)
sign_in #user
end
end
end
routes
devise_for :users
devise_for :admins, :class_name => 'User'
One solution is to set cache_classes = false, however that isn't ideal as I use spork and don't want to have to restart it after changing a model.
Any help?

I have something like this in my routes:
devise_for :accounts, :controllers => {:confirmations => "confirmations"} do
put "confirm_account", :to => "confirmations#confirm_account"
get "login" => "devise/sessions#new", :as => :login
delete "logout" => "devise/sessions#destroy", :as => :logout
get "register" => "devise/registrations#new", :as => :register
end
so in my spec/support/controller_macros.rb I needed to change from:
def login_account
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:account]
#account = Factory.create(:account)
sign_in(#account)
end
end
to
def login_account
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:account]
#account = Factory.create(:account)
sign_in(:account, #account)
end
end
note the sign_in(scope, resource)
I hope this helps.

This is from the devise readme:
Devise also ships with default routes.
If you need to customize them, you
should probably be able to do it
through the devise_for method. It
accepts several options like
:class_name, :path_prefix and so on,
including the possibility to change
path names for I18n
So I would check your routes file and make sure this is in there:
devise_for :admins, :class_name => 'User'

You may want to check your code for multiple devise_for :admins declarations in different places. This has been the cause of such an exception in my case, as it surely confuses Devise.

Related

Rspec controller error? expecting <"index"> but rendering with <""> or it's working?

I'm new with rspec test and maybe there are something that I dont undertand.
if can any help me, I really appreciate some help.
File Structure:
app/models/booking.rb
app/models/user.rb
app/models/role.rb
app/models/ability.rb
app/controllers/bookings_controller.rb
app/views/bookings/index.html.erb
app/views/dashboard/index.html.erb
app/spec/controllers/bookings_controller_spec.rb
I read this link with a similar problem but it isn't solved
Rspec controller error expecting <"index"> but rendering with <"">
is similar, because if I change this line:
it 'should not render index template from bookings' do
get :index
=> response.should_not render_template(:index)
end
for this other:
it 'should not render index template from bookings' do
get :index
=> response.should render_template(:index)
end
I get the same mistake that in the link
expecting <"index"> but rendering with <"">
and I don't know why?
Here's my Code:
My Spec:
describe BookingsController do
context 'as guest' do
before(:each) do
#user = User.new(:email => 'mail_admin#test.com',
:username => 'admin',
:password => 'password_admin',
:password_confirmation => 'password_admin')
#user.save
#when i save, with gem CanCan i assign a default role to #user
#with the default role the user only can see the views/dashboard/index.html.erb
end
it 'should not render index template from bookings' do
get :index
response.should_not render_template(:index)
end
end
end
Controller:
class BookingsController < ApplicationController
load_and_authorize_resource
def index
...
end
def show
...
end
end
My model:
class Booking < Activerecord::Base
paginates_per 20
def
...
end
def
...
end
end
User:
Class User < ActiveRecord::Base
after_save :set_default_role
rolify
.
.
.
.
def set_default_role
self.add_role :default
end
end
Role:
class Role < ActiveRecord::Base
ROLES = {"admin" => "Admin", "default" => "Default"}
.
.
.
.
scopify
end
Ability:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.has_role? :admin
can :manage, :all
elsif user.has_role? :data_consistency
can :read, Booking
end
end
end
CanCan authorizes model access not controller actions. For most other actions these two are more or less the same thing, but not for the index. On the index action CanCan adds a scope to the query for records that includes your authorization restrictions.
What this means is that your guest user will simply not be able to see any records, but the view will still render.
What you want is authentication (ie Devise) and use it from a before_filter in each controller that requires an authenticated user to access.
class BookingsController < ApplicationController
load_and_authorize_resource # Handles authorization
before_filter !authenticate_user # Handles authentication (included with Devise)
...
end
In my case, the problem was solved in before(:each) block!
My code works like this:
before :each do
#user = User.new(:email => 'mail_admin#test.com',
:username => 'admin',
:password => 'password_admin',
:password_confirmation => 'password_admin')
#user.confirm!
sign_in #user
end

Rails 3 Correctly routing the destroy action for a session

I am refactoring my access_controller into a sessions_controller and can't seem to get my destroy action working properly.
Logging in seems to work fine, but I am unable to log out of a session. Here is the link I have for logging out:
<%= link_to("Logout", :controller => "sessions", :action => 'destroy') %>
routes.rb
resources :sessions
sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
...
end
def destroy
session[:user_id] = nil
flash[:notice] = "You are now logged out"
redirect_to root_url
end
end
When I click "Logout" I get redirected to "/sessions/destroy" with a message of "The action 'show' could not be found for SessionsController". The destroy actions seems to want an id, but I don't need to pass in an id, I just want to run the action.
Ah, I found the answer here: http://railscasts.com/episodes/250-authentication-from-scratch
I need to set up my routes as follows:
get "log_out" => "sessions#destroy", :as => "log_out"
get "log_in" => "sessions#new", :as => "log_in"
resources :sessions

Unable to delete resource after overriding devise registrations controller

I have followed this devise how to: Redirect to a specific page on successful sign up.
I have created a new RegistrationsController
class RegistrationsController < Devise::RegistrationsController
def after_inactive_sign_up_path_for(resource)
...
end
def destroy
logger.debug 'destroy user'
...
end
end
I have changed routes.rb :
devise_for :users, :controllers => { :registrations => "registrations" } do
get 'users', :to => 'profile#index', :as => :user_root
end
and moved devise/registrations/ views under my new RegistrationsController.
With rake routes I have :
DELETE /users(.:format) {:action=>"destroy", :controller=>"registrations"}
after_inactive_sign_up_path_for is working.
But destroy action doesn't work : when I cancel my account
<%= button_to "Cancel my account", registration_path(resource_name), :confirm => "ok?", :method => :delete %>
I have the following error :
The action 'destroy' could not be found for RegistrationsController
I use Devise 1.4.5 & Rails 3.1
I just ran into the same issue. Moving the destroy method to the non private section of the controller fixed it.

rspec controller test with devise authentication

I am having problem with rspec testing controller the devise authentication.
I have a following setup
I have included
config.include Devise::TestHelpers, :type => :controller
in my spec_helper.rb
In my merchants_controller_spec.rb
describe MerchantsController do
before :each do
#user = Factory(:user)
#merchant = Factory(:merchant, :user_id => #user.id,:is_approved => false, :is_blacklisted => false)
controller.stub!(:current_user).and_return(#user)
end
describe "GET index" do
it "assigns all merchants as #merchants" do
merchant = Factory(:merchant,:is_approved => true, :is_blacklisted => false)
get :index
assigns(:merchants).should eq([merchant])
end
end
end
My merchants_controller.rb
class MerchantsController < ApplicationController
before_filter :authenticate_user!
def index
#merchants = Merchant.approved
debugger
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #merchants }
end
end
end
I have a scope approved in merchant model
scope :approved, where(:is_approved => true, :is_blacklisted => false)
Now my problem is even though i stubbed current_user and returned #user as current_user, My merchants_controller index spec is failing. But if i comment out authenticate_user! then the spec passes,
without authenticate_user! the debugger of index action is caught but with authenticate_user! debugger is not caught.
I think there is problem in subbing current_user and i am not able to figure it out.
Help me out..
Have you read through the docs on github?:
Devise includes some tests helpers for functional specs. To use them, you just need to include Devise::TestHelpers in your test class and use the sign_in and sign_out methods. Such methods have the same signature as in controllers:
sign_in :user, #user # sign_in(scope, resource)
sign_in #user # sign_in(resource)
sign_out :user # sign_out(scope)
sign_out #user # sign_out(resource)
Another alternative
RSpec.describe YourController, :type => :controller do
before do
user = FactoryGirl.create(:user)
allow(controller).to receive(:authenticate_user!).and_return(true)
allow(controller).to receive(:current_user).and_return(user)
end
# rest of the code
end

Troubleshooting two-step nested model signup process

I want to initiate a sign-up process on my homepage. In the end, the process ideally would follow the following logic:
user = User.new
user.email = ""
user.password = ""
user.profile = Profile.new
user.profile.info = ""
user.profile.save
user.save
I'll be using nested model forms, of course. But is there a way to spread this into two parts? In part 1 the User would enter mainly user information, as well as a bit of profile information, and part 2 would contain solely 'profile' information. Then when all is said and done the user gets redirected to their user profile.
If this is possible, what is the general thinking on this type of process? Second, I'm wondering if someone can help me figure out how to achieve it. I have the nested model forms all set up but there must be something messed up in my routes.rb file/Controllers that is denying me the experience.
Here's my routes.rb file.
get "profiles/show"
get "/profiles/:id" => "profiles#show", :as => "profile"
post "/signup" => "profiles#create", :as => "signup"
get "skip/signup", :to => "users#newskip"
match "skip/profiles/new", :to => "profiles#newskip"
root :to => "users#new"
And here are my UsersController and ProfilesController respectively:
*class UsersController < ApplicationController*
before_filter :authenticate, :only => [:edit, :update]
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to signup_path, :notice => 'User successfully added.'
else
render :action => 'new'
end
end
*class ProfilesController < ApplicationController*
before_filter :authenticate, :only => [:edit, :update]
def new
#user.profile = Profile.new
end
def create
#profile = Profile.new(params[:profile])
if #profile.save
redirect_to profile_path(#profile), :notice => 'User successfully added.'
else
render :action => 'new'
end
end
Can anyone help show me the light? I know Devise is a solution but I'm trying to learn without that. At least at first. This previous question/answer looks like a potential starter.
Here is a Railscast about multistep forms. I think it should put you on track for what you're trying to accomplish.
I completed this by having user and profile create on the homepage, Profiles#edit as the second step, with a redirect_to profile.