Rspec controller error: No route matches {:controller=>"bookings", :action=>"/dashboard/index"} - ruby-on-rails-3

I'm getting an error when I try to test mi controller, I'm new with rspec test and maybe there are something that I dont undertand.
$rspec spec/controllers/booking_controller_spec.rb
I get the following error:
No route matches {:controller=>"bookings", :action=>"/dashboard/index"}
and I don't understand why? so 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
My fail 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
it 'should render index template from dashboard' do
get '/dashboard/index'
response.should 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

Related

Clearance failure when forbidden password reset

I’m using clearance and love it, but I'm having trouble resetting passwords. I type in my email to reset the password, which works, but then when I try to navigate to the edit password page using the reset token, I get the failure when forbidden flash error “Please double check the URL or try submitting the form again” and it redirects me back. I get the same error in my tests.
I think this has something to do with my before_action statements, but I just don’t know how to fix them. I have researched questions like this to no avail.
I'm sure it's a stupid question, but I'm new so I really appreciate any help. Please let me know if this isn't enough code.
class UsersController < Clearance::UsersController
before_action :require_login, only: [:create] # does this need to be in both user controllers?
...
def user_params
params.require(:user)
end
end
And here is the clearance controller.
class Clearance::UsersController < ApplicationController
before_action :require_login, only: [:create]
require 'will_paginate/array'
def new
#user = user_from_params
render template: 'users/new'
end
def create
#user = user_from_params
#user.regenerate_password
if #user.save
sign_in #user unless current_user
UserMailer.welcome_email(#user).deliver!
redirect_to users_path
else
render template: 'users/new'
end
end
def edit
#user = User.friendly.find(params[:id])
end
def update
#user = User.friendly.find(params[:id])
if #user.update(permit_params)
redirect_to #user
flash[:success] = "This profile has been updated."
else
render 'edit'
end
end
private
def avoid_sign_in
redirect_to Clearance.configuration.redirect_url
end
def url_after_create(user)
dashboards_path(user)
end
def user_from_params
user_params = params[:user] || Hash.new
is_public = check_public_params(user_params)
first_name = user_params.delete(:first_name)
last_name = user_params.delete(:last_name)
email = user_params.delete(:email)
password = user_params.delete(:password)
parish = user_params.delete(:parish)
division = user_params.delete(:division)
admin = user_params.delete(:admin)
Clearance.configuration.user_model.new(user_params).tap do |user|
user.first_name = first_name
user.last_name = last_name
user.password = password
user.email = email
user.is_public = is_public
user.parish_id = parish.to_i
user.division = division
user.admin = admin
end
end
def permit_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :is_public, :parish_id, :division, :admin)
end
end
EDIT: relevant portions of routes.rb
Rails.application.routes.draw do
resources :passwords, controller: "clearance/passwords", only: [:create, :new]
resource :session, controller: "clearance/sessions", only: [:create]
resources :users, controller: "clearance/users", only: [:create] do
resource :password,
controller: "clearance/passwords",
only: [:create, :edit, :update]
end
get "/sign_in" => "clearance/sessions#new", as: "sign_in"
delete "/sign_out" => "clearance/sessions#destroy", as: "sign_out"
get "/sign_up" => "clearance/users#new", as: "sign_up"
constraints Clearance::Constraints::SignedOut.new do
root to: 'high_voltage/pages#show', id: 'landing'
end
constraints Clearance::Constraints::SignedIn.new do
# root to: 'dashboards#index', as: :signed_in_root
root to: 'high_voltage/pages#show', id: 'parish_dashboard', as: :signed_in_root
end
# constraints Clearance::Constraints::SignedIn.new { |user| user.admin? } do
# root to: 'teams#index', as: :admin_root
# end
resources :users do
collection { post :import }
end
It turns out there was a conflict between the way I was finding the user instance in the password reset link. Clearance finds users simply by using #user, but since I'm using FriendlyId I needed to change that to #user.id.
So instead of...
<%= link_to 'Change My Password', edit_user_password_url(#user, token: #user.confirmation_token.html_safe) %>
I did
<%= link_to 'Change My Password', edit_user_password_url(#user.id, token: #user.confirmation_token.html_safe) %>
Thanks, Thoughbot, for this great gem!

Allow non registered users to view content with pundit

I have having trouble allowing non-registered/non-logged in users to view the index and show pages for a blog section. I am using Pundit for authorization and realize that at the moment I have my policies set to not allow non-users to view any part of the blog section, but I have no idea how to work around that to have no policy for the index and show page.
My goal is to have the following:
Allow Admin and Editors to view, create, edit, and delete blogs
This portion works pefect
Allow registered users to view blogs
This portion works perfect
Allow non-registered/non-logged in users to view blogs
This part does not work
When I try to view the index page as a non-registered/non-logged in user, I will get an access denied flash message that comes out of my application controller, which is doing what it is supposed to be doing given the current policies.
So my question is: How do I modify my policies to allow non-registered/non-logged in users to view the index and show pages only?
Application Controller
class ApplicationController < ActionController::Base
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :configure_permitted_parameters, if: :devise_controller?
private
def user_not_authorized(exception)
flash[:danger] = "Access denied. You are not authorized to view that page."
redirect_to (request.referrer || root_path)
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me) }
devise_parameter_sanitizer.permit(:sign_in) { |u| u.permit(:username, :email, :password, :remember_me) }
devise_parameter_sanitizer.permit(:account_update) {|u| u.permit(:username, :email, :password, :password_confirmation, :current_password)}
end
end
Application Policy
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
raise Pundit::NotAuthorizedError, "You must be logged in to perform this action" unless user
#user = user
#record = record
end
def index?
true
end
def show?
scope.where(:id => record.id).exists?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
scope
end
end
end
Post Policy
class PostPolicy < ApplicationPolicy
attr_reader :post
class Scope < Scope
def resolve
if user&.admin?&.editor?&.user?
scope.all
else user != admin? || editor? || user?
scope
end
end
end
def permitted_attributes
if user.admin? || user.editor?
[:title, :body, :image, :permalink, :description, :tag_list, :username]
else
[:title, :body, :image, :username]
end
end
def index?
true
end
def show?
true
end
def new?
user.admin? || user.editor?
end
def create?
user.admin? || user.editor?
end
def update?
user.admin? || user.editor?
end
def destroy?
user.admin? || user.editor?
end
end
Post Controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
after_action :verify_authorized, only: [:destroy]
def index
#meta_title = "Blog"
#meta_description = "page description here"
#posts = Post.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 4)
end
def show
#meta_title = #post.title
#meta_description = #post.description
end
def new
#meta_title = "Add New Blog"
#meta_description ="Add a new blog."
#post = Post.new
authorize #post
end
def edit
#meta_title = "Edit Blog"
#meta_description ="Edit an existing blog."
authorize #post
end
def create
#post = Post.new
#post.update_attributes(permitted_attributes(#post))
#post.user = current_user if user_signed_in?
authorize #post
if #post.save
redirect_to #post, notice: 'Post was successfully created.'
else
render :new
end
end
def update
#post = Post.find(params[:id])
if #post.update_attributes(permitted_attributes(#post))
authorize #post
redirect_to #post, notice: 'Post was successfully updated.'
else
render :edit
end
end
def destroy
if #post.present?
#post.destroy
authorize #post
else
skip_authorization
end
redirect_to posts_url, notice: 'Post was successfully deleted.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Only allow the white list through.
def post_params
params.require(:post).permit(policy(#post).permitted_attributes)
end
end
I've seen a similar question asked Pundit policy_scoper error, but the solution suggested there does not seem to work in my case.
After much frustration, I was finally able to solve the issue. Big thanks go out to #Scott for helping get the controller and testing set up as they should be, and nearly getting the policies working.
Turns out that the raise Pundit::NotAuthorizedError, "must be logged in" unless user in the initializer section of the Application Policy was not allowing non-logged-in users from accessing the index page (just like it's supposed to when you want a closed system...). Since my application is open for anyone to view in the index and show pages of the blog, I needed to remove that line.
Once removed the application would then throw a undefined method admin?' for nil:NilClass for non-logged-in users trying to access the blog index page. This was solved by using the correct conventions of identifying users in Post Policy. For each def in the policy I had user.admin? || user.editor?. That needed to be changed to user&.admin? || user&.editor?.
The code ended up as follows:
Application Policy
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
def index?
false
end
def show?
scope.where(:id => record.id).exists?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
scope
end
end
end
Post Policy
class PostPolicy < ApplicationPolicy
attr_reader :post
class Scope < Scope
def resolve
if user&.admin? || user&.editor?
scope.all
else
end
end
end
def permitted_attributes
if user.admin? || user.editor?
[:title, :body, :image, :permalink, :description, :tag_list, :username]
else
[:title, :body, :image, :username]
end
end
def index?
true
end
def show?
true
end
def new?
admin_or_editor
end
def create?
admin_or_editor
end
def update?
admin_or_editor
end
def destroy?
admin_or_editor
end
private
def admin_or_editor
user&.admin? || user&.editor?
end
end
Post Controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
after_action :verify_authorized, except: [:index, :show]
def index
#meta_title = "Blog"
#meta_description = "blog description"
#posts = Post.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 4)
end
def show
#meta_title = #post.title
#meta_description = #post.description
end
def new
#meta_title = "Add New Blog"
#meta_description ="Add a new blog."
#post = Post.new
authorize #post
end
def edit
#meta_title = "Edit Blog"
#meta_description ="Edit an existing blog."
authorize #post
end
def create
#post = Post.new
#post.update_attributes(permitted_attributes(#post))
#post.user = current_user if user_signed_in?
authorize #post
if #post.save
redirect_to #post, notice: 'Post was successfully created.'
else
render :new
end
end
def update
#post = Post.find(params[:id])
authorize #post
if #post.update_attributes(permitted_attributes(#post))
redirect_to #post, notice: 'Post was successfully updated.'
else
render :edit
end
end
def destroy
if #post.present?
#post.destroy
authorize #post
else
skip_authorization
end
redirect_to posts_url, notice: 'Post was successfully deleted.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Only allow the white list through.
def post_params
params.require(:post).permit(policy(#post).permitted_attributes)
end
end

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

CanCan not authorizing nested resource

I have a Ticket model and a TicketReply model:
class Ticket < ActiveRecord::Base
has_many :replies, :class_name => "TicketReply"
end
class TicketReply < ActiveRecord::Base
belongs_to :ticket, :class_name => "Ticket"
end
Here is my list of abilities:
class Ability
include CanCan::Ability
def initialize(user)
can :manage, Ticket, :userid => user.id
can :manage, TicketReply, :ticket => { :userid => user.id }
end
end
And finally my TicketRepliesController:
class TicketRepliesController < AuthorizedController
load_and_authorize_resource :ticket
load_and_authorize_resource :ticket_reply, :through => :ticket
def create
if #ticket_reply.valid?
# ...
else
# ...
end
end
end
However, every time I try to create a ticket reply I get an unauthorized message: "You are not authorized to access this page.".
EDIT: I can access the Ticket itself fine through a TicketsController.
Any idea what I am missing?
In the controller new and create actions, you need to wire your new ticket record with the current_user
class TicketRepliesController < AuthorizedController
... whatever code you have
protected
# override to do the wireing
def build_resource
resource = super
resource.userid = current_user.id # wired!
resource
end
end
Now CanCan will see the link and allow!

Issue with setting values to a model in rails

I have a model named User . I am using Devise for authentication.
The 'User' has many 'Profiles' and one default profile . So I have added a column called 'default' to the User model. I want to store the id of the default profile.
However the code fails at the current_user.default = statement.
Error - undefined method `default=' for #User:0x402c480
class User < ActiveRecord::Base
..........
has_many :profiles
...........
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :default
end
.......
class ProfilesController < ApplicationController
before_filter :authenticate_user! ,:except => [:show]
def create
#profile = current_user.profiles.new(params[:profile])
#profile.user = current_user
respond_to do |format|
if #profile.save
#current_user.default= #profile.id
............
end
How do I go about this ? Adding 'default' to the User model doesnt solve the problem.
I suggest you to use STI, it means add "type" column into 'profiles' table
class User < ActiveRecord::Base
has_many :profiles
has_one :profile_default
after_create do
create_profile_default
end
end
class Profile < ActiveRecord::Base
end
class ProfileDefault < Profile
end
def create
#profile = current_user.profiles.new(params[:profile])
#profile.user = current_user
respond_to do |format|
if #profile.save
...
end