smallseo.info

cancan

Authorization Gem for Ruby on Rails.

Why is this rspec request spec not updating the model?

I have a requests spec for interactions with the User model. I want to make sure that Users with the Admin role can create/edit/destroy Users. I'm having a problem right now where the Edit action does not update the user. Everything works properly when I manually go through the actions on the site itself, but the tests fail to update the user.

Here's my spec:

it 'edits a user' do
  @user = FactoryGirl.create(:user)
  visit new_user_session_path unless current_path == new_user_session_path
  fill_in "Email", :with => @user.email
  fill_in "Password", :with => @user.password
  click_button "Sign In"
  user_to_edit = FactoryGirl.create(:user, first_name: "John", last_name: "Smith")
  visit edit_user_path(user_to_edit) unless current_path == edit_user_path(user_to_edit)
  fill_in 'user_last_name', with: "Changed"
  expect{
    click_button "Do it"
  }.to change { user_to_edit.last_name }.from("Smith").to("Changed")
  page.should have_content "John Changed"
end

The error that I get is:

Failure/Error: expect{
       result should have been changed to "Changed", but is now "Smith"

If I change the last few lines of the test to this:

  fill_in 'user_last_name', with: "Changed"
  click_button "Do it"
  page.should have_content "John Changed"

Then the test succeeds. This doesn't seem right, since the page should not display "John Changed" if user_to_edit was not updated.

My Delete request spec works fine:

it "deletes a user" do
  @user = FactoryGirl.create(:user)
  visit new_user_session_path unless current_path == new_user_session_path
  fill_in "Email", :with => @user.email
  fill_in "Password", :with => @user.password
  click_button "Sign In"
  user_to_delete = FactoryGirl.create(:user, first_name: "John", last_name: "Smith")
  visit users_path unless current_path == users_path
  expect{
    within ".user_#{user_to_delete.id}" do
      click_link 'Delete'
    end
  }.to change(User,:count).by(-1)
  page.should_not have_content "John Smith"
end

I have a user model:

class User < ActiveRecord::Base
  ROLES = %w[renter landlord admin]
  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
  attr_accessible :email, :password, :password_confirmation :first_name, :last_name, :role

  validates :password, :presence => true, :on => :create
  validates :first_name, :presence => true
  validates :last_name, :presence => true

  before_save :set_phones

  def set_phones
    self.fax = Phoner::Phone.parse(self.fax).format("%a%n") unless self.fax.blank?
    self.land_phone = Phoner::Phone.parse(self.land_phone).format("%a%n") unless land_phone.blank?
    self.mobile_phone = Phoner::Phone.parse(self.mobile_phone).format("%a%n") unless mobile_phone.blank?
  end
end

I have this factory:

require 'faker'

FactoryGirl.define do
  factory :user do |f|
    f.first_name { Faker::Name.first_name }
    f.last_name { Faker::Name.last_name }
    f.email {Faker::Internet.email}
    f.password { "oq2847hrowihgfoigq278o4r7qgo4" }
    f.role { "admin" }
  end
end

I have these actions in my user controller:

  def edit
    @user = User.find_by_id(params[:id])

    respond_to do |format|
      format.html
    end
  end

  def update
    if params[:user][:password].blank?
      [:password,:password_confirmation].collect{|p| params[:user].delete(p) }
    end

    respond_to do |format|
      if @user.errors[:base].empty? and @user.update_attributes(params[:user])
        flash.now[:notice] = "Your account has been updated"
        format.html { render :action => :show }
      else
        format.html { render :action => :edit, :status => :unprocessable_entity }
      end
    end
  end

The routes.rb file is also relevant, since I'm using Devise and have a custom Users Controller:

  devise_for :users, :skip => [:sessions, :registrations]

  devise_scope :user do
    get "login" => "devise/sessions#new", :as => :new_user_session
    post 'login' => 'devise/sessions#create', :as => :user_session
    delete "logout" => "devise/sessions#destroy", :as => :destroy_user_session
    get "signup" => "devise/registrations#new", :as => :new_user_registration
    put "update-registration" => "devise/registrations#update", :as => :update_user_registration
    delete "delete-registration" => "devise/registrations#destroy", :as => :delete_user_registration
    get "edit-registration" => "devise/registrations#edit", :as => :edit_user_registration
    get "cancel-registration" => "devise/registrations#cancel", :as => :cancel_user_registration
    post "create-registration" => "devise/registrations#create", :as => :user_registration
  end

  resources :users, :controller => "users"

Source: (StackOverflow)

CanCan - Access denied - Way to make CanCan Specify in the LOG Why?

I'm working to implement CanCan. For some reason CanCan keeps giving me Access Denied when I try to get specific about model permissions. And I can't figure out why.

Is there a way to get CanCan to be specific, perhaps in the logs or in development about Why Access is denied? something like, No Read Ability to XXX Model.

That would be helpful for debugging.

Thanks


Source: (StackOverflow)

Admin Authorization w/ CanCan

A have a bunch of controllers w/ the Admin namespace. I want to restrict access to these unless the user is an admin. Is there a way to do this using CanCan without having to call unautorized! in every method of every controller?


Source: (StackOverflow)

Serialize permissions (e.g. CanCan) with active_model_serializers

How do I serialize permissions with active_model_serializers? I don't have access to current_user or the can? method in models and serializers.


Source: (StackOverflow)

How can I use RSpec to test the response code on a CanCan failed authorization?

I'm working on a rails project in which I use CanCan to authorize my resources. When a user is not signed in and tries to submit a "talk" (via an ajax form submission), CanCan correctly raises a 401 with {"status":"error","message":"You must be logged in to do that!"} as the response (I have verified this in the browser using firebug). However, in my tests get a 302 response code rather than a 401:

class TalksController < ApplicationController
  authorize_resource

  def create
    @talk = current_user.talks.build(params[:talk])

    respond_to do |format|
      if @talk.save
        response = { :redirect => talk_path(@talk) }
        format.html { redirect_to @talk, notice: 'Talk was successfully created.' }
        format.json { render json: response, status: :created,  }
      else
        format.html { render action: "new" }
        format.json { render json: @talk.errors, status: :unprocessable_entity }
      end
    end
  end
end

talks_controller_spec.rb:

describe TalksController do
  describe "POST create" do
    context "when not signed in" do
      it "should not assign talk" do
        post :create
        assigns[:talk].should be_nil
      end
      it "should respond with a 401" do
        post :create
        response.response_code.should == 401
      end
    end
  end
end

The first example included here is successful (assigns[:talk] does not get assigned), but the second is not:

1) TalksController POST create when not signed in should respond with a 401
     Failure/Error: response.response_code.should == 401
       expected: 401
            got: 302 (using ==)
     # ./spec/controllers/talks_controller_spec.rb:53:in `block (4 levels) in <top (required)>'

I'm not sure exactly what's going on. Is there a way I can test for the actual response code returned to the browser? Or a better way I can test the authorization?


Source: (StackOverflow)

Rails Can Can Ability Class For Multiple Devise Models

I was wondering how I can define an ability class and serve that ability class depending on the user that has logged in.

I am using Active Admin, Can Can and Devise and I have successfully created a User and an AdminUser models.

I have this in my ability.rb

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new

    if (user)
      can :manage, Item
    end
  end
end

Now I have used this wiki entry to determine that we can indeed define a custom ability file and use that instead of the ability.rb:

https://github.com/ryanb/cancan/wiki/changing-defaults

But what I wanted to do is, be able to use ability.rb if a "non-admin user" is signed in and a custom abilty if a user admin is signed in.

Side Question: Could it be done such that I don't need a custom one and I could set permissions in one ability.rb file?


Source: (StackOverflow)

Using cancan to prevent access to controller

I have an admin controller and I want that only users that are defined as admin would have access to that controller.

my ability class:

class Ability
  include CanCan::Ability

  def initialize(user)
    if user.admin?
      can :manage, :all
    else
      can :read, :all
    end
  end
end

my admin controller:

class AdminController < ApplicationController
  load_and_authorize_resource

  def index
  end

  def users_list
  end
end

when i try to access /admin/users_list (either with an admin user or without) i get the following error: uninitialized constant Admin

What am I doing wrong? Is that the right way to restrict access to a controller?


Source: (StackOverflow)

CanCan difference between :read and [:index, :show]?

According to all documentation, the :read action is aliased to both :index and :show:

alias_action :index, show, :to => :read

However, consider the following scenario with nested resources:

resources :posts
  resources :comments
end

If I define abilities like this:

# ability.rb
can :read, Post
can :show, Comment

# comments_controller.rb
load_and_authorize_resource :organization, :find_by => :permalink
load_and_authorize_resource :membership, :through => :organization

things work as expected. However, if I change the :read action to [:index, :show]:

# ability.rb
can [:index, :show], Post
can :show, Comment

# comments_controller.rb
load_and_authorize_resource :organization, :find_by => :permalink
load_and_authorize_resource :membership, :through => :organization

I am unauthorized to access /posts/:post_id/comments, /posts/:post_id/comments/:id, etc. I still, however, can access both :index and :show for the posts_controller.

How is possible that these actions are "aliased", if they behave differently?

In my fiddling, I also came across the following. Changing load_and_authorize_resource to the following allowed access:

# ability.rb
can [:index, :show], Post
can :show, Comment

# comments_controller.rb
load__resource :organization, :find_by => :permalink
load_and_authorize_resource :membership, :through => :organization

Can someone explain what's going on here?


Source: (StackOverflow)

What is current_ability in cancan's accessible_by (fetching records)?

In the documentation of cancan it shows how to fetch all accessible records (in http://wiki.github.com/ryanb/cancan/fetching-records) in this way:

@articles = Article.accessible_by(current_ability)

but what is current_ability? I've tried passing the current user which I'm using for authentication and authorization, but I've got this error:

NoMethodError: undefined method `conditions' for #<User:0x1092a3b90>

Any ideas what should I pass to accessible_by or what's wrong here?


Source: (StackOverflow)

RSpec authorization testing with raise_error not working

I'm trying to test how a not logged in user behaves like this

  describe "not logged in user" do
   user_no_rights

    it "can't access action index" do
      expect(get :index).to raise_error(CanCan::AccessDenied)
    end
  end

The output when i run rspec

  Failure/Error: expect(get :index).to raise_error("CanCan::AccessDenied:You are not authorized to access this page.")
     CanCan::AccessDenied:
       You are not authorized to access this page.

So it looks like the correct execption is raised, but why is the spec not passing?


Source: (StackOverflow)

How do I create an rspec test that validates a JSON response?

I have a Groups Controller with a method def inbox.

If the user is a group member then inbox returns a JSON object.

if the user is not a member, then inbox should redirect thanks to CanCan permissions.

How do I write an rspec to test these two use cases?

Thanks

Current spec:

require 'spec_helper'

describe GroupsController do
  include Devise::TestHelpers

  before (:each) do
    @user1 = Factory.create(:user)
    @user1.confirm!
    sign_in @user1
    @group = Factory(:group)
    @permission_user_1 = Factory.create(:permission, :user => @user1, :creator_id => @user1.id, :group => @group)
  end

  describe "GET inbox" do
    it "should be successful" do
      get inbox_group_path(@group.id), :format => :json
      response.should be_success
    end
  end
end

Rake Routes:

inbox_group GET    /groups/:id/inbox(.:format)                                                                       {:controller=>"groups", :action=>"inbox"}

Routes File:

  resources :groups do
    member do
      get 'vcard', 'inbox'
    end
    ....

Source: (StackOverflow)

CanCanCan throws a regular Rails error on an exception rather than a flash message like I specified

I am using CanCanCan, Devise & Rolify.

My ApplicationController looks like this:

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception
  before_filter :new_post

  rescue_from CanCan::AccessDenied do |exception|
    redirect_to root_url, :alert => exception.message
  end

  def new_post
    @post = Post.new
  end  

end

My routes.rb looks like this:

  authenticate :user, lambda { |u| u.has_role? :admin or :editor } do
    get 'newsroom', to: 'newsroom#index', as: "newsroom"
    get 'newsroom/published', to: 'newsroom#published'
    get 'newsroom/unpublished', to: 'newsroom#unpublished'    
  end

# truncated for brevity
  root to: "posts#index"

This is my ability.rb that is relevant:

elsif user.has_role? :member
    can :read, :all
    cannot :read, :newsroom

So when I am logged in as :member, and I try to go to /newsroom, I get this error:

NameError at /newsroom
uninitialized constant Newsroom

Rather than being redirected to the root_url with an :alert like I would have expected.

Not sure what's happening here.

Edit 1

For what it's worth, I only get this when I add this to my NewsroomController:

authorize_resource

Source: (StackOverflow)

Safest and Railsiest way in CanCan to do Guest, User, Admin permissions

I'm relatively new to rails (3), and am building an application, using CanCan, where there are 3 tiers of users.

  • Guest - unregistered visitor User
  • registered and logged in visitor
  • Admin - registered and logged in visitor with admin flag

My ability is bog-stock right now, copied from cancan docs, basically defining the guest role and the admin role

class Ability

    include CanCan::Ability

    def initialize(user)
        user ||= User.new # Guest user

        if user.is_admin?
            can :manage, :all
        else
            can :read, [Asana,Image,User,Video,Sequence]
        end
    end

end

I'm looking to add in the user role. Since I'm creating that throwaway user model, I thought about using new_record? to determine if the user is logged in or not. Something like:

class Ability

    include CanCan::Ability

    def initialize(user)
        user ||= User.new # Guest user

        if !user.new_record? and user.is_admin?
            can :manage, :all
        elsif !user.new_record? and !user.is_admin?
            can {registered user-y permissions}
        else
            can :read, [Asana,Image,User,Video,Sequence]
        end
    end

end

But, it just doesn't feel right. Seems kind of disassociated from, like, actual logged-in-ed-ness, and have concerns about whether its actually secure.

Looking for advice on a more elegant way to doing this.

Thanks!


Source: (StackOverflow)

cancan skip_authorization_check for Devise authentication

Because anyone can sign up and then log in,... and because a user isn't identified for roles until after log in, doesn't it make sense to skip authorization_check for Devise?

Going on that premise, i inherit from the Devise registration controller with this registrations_controller and placed it in the controller directory.

class Users::RegistrationsController < Devise::RegistrationsController
  skip_authorization_check
end

change to the routes file:

devise_for :users, :controllers => { :registrations => "registrations" }

I'm missing something though:

This action failed the check_authorization because it does not authorize_resource. Add skip_authorization_check to bypass this check.

Thanks for your help.


Source: (StackOverflow)

CanCan load_and_authorize_resource triggers Forbidden Attributes

I have a standard RESTful controller that uses strong parameters.

class UsersController < ApplicationController
  respond_to :html, :js

  def index
    @users = User.all
  end

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def edit
    @user = User.find(params[:id])
  end

  def create
    @user = User.new(safe_params)

    if @user.save
      redirect_to @user, notice: t('users.controller.create.success')
    else
      render :new
    end
  end

  def update
    @user = User.find(params[:id])

    if @user.update_attributes(safe_params)
      redirect_to @user, notice: t('users.controller.update.success')
    else
      render :edit
    end
  end

  def destroy
    @user = User.find(params[:id])

    if current_user != @user
      @user.destroy
    else
      flash[:error] = t('users.controller.destroy.prevent_self_destroy')
    end
    redirect_to users_url
  end

  private

  def safe_params
    safe_attributes =
      [
        :first_name,
        :last_name,
        :email,
        :password,
        :password_confirmation,
      ]
    if current_user.is?(:admin)
      safe_attributes += [:role_ids]
    end
    params.require(:user).permit(*safe_attributes)
  end
end

In my config/initializers I have the file strong_parameters.rb

ActiveRecord::Base.send(:include,  ActiveModel::ForbiddenAttributesProtection)

When I add a simple call to CanCan's load_and_authorize_resource I get

1) UsersController POST create with invalid params re-renders the 'new' template
 Failure/Error: post :create, user: @attr
 ActiveModel::ForbiddenAttributes:
   ActiveModel::ForbiddenAttributes
 # ./spec/controllers/users_controller_spec.rb:128:in `block (4 levels) in <top (required)>'

Where @attr in the test is defined as

  before(:each) do
    @attr =
      {
        first_name: "John",
        last_name: "Doe",
        email: "user@example.com",
        password: "foobar",
        password_confirmation: "foobar"
      }
  end

In the tests I have it all setup properly to login the user and give them the necessary roles for being an administrator so I know it's not that. I don't know why this is causing ForbiddenAttributes to trigger. I'm sure it's something simple I've overlooked. Has anyone else encountered this problem and found a solution to it?


Source: (StackOverflow)