27.02.2013 Views

Rails%203%20In%20Action

Rails%203%20In%20Action

Rails%203%20In%20Action

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Restricting write access<br />

(There’s no particular reason to put this gem underneath Devise other than that it’s<br />

sensible to group together gems dealing with similar functions.) To install the CanCan<br />

gem, run bundle install.<br />

8.5.4 Adding abilities<br />

When you run bin/rspec spec/controllers/tickets_controller_spec.rb, you get<br />

this output:<br />

Failure/Error: get :new, :project_id => project.id<br />

uninitialized constant Ability<br />

This error occurs because CanCan is now defining the cannot? method for the controller,<br />

which uses a CanCan in-built method called current_ability:<br />

@current_ability ||= ::Ability.new(current_user)<br />

The ||= sets @current_ability if it isn’t already set. The :: before Ability indicates<br />

to Ruby that you want the Ability at the root namespace. This allows you to have a<br />

module called CanCan::Ability and a class at Ability and to differentiate between<br />

the two. In this example, it’s trying to access just Ability, which is a class that doesn’t<br />

yet exist.<br />

This new Ability class will provide the link between users and their permissions.<br />

You define it in a new file at app/models/ability.rb exactly like the following listing.<br />

Listing 8.8 app/models/ability.rb<br />

class Ability<br />

include CanCan::Ability<br />

def initialize(user)<br />

user.permissions.each do |permission|<br />

can permission.action.to_sym,<br />

➥permission.thing_type.constantize do |thing|<br />

thing.nil? ||<br />

permission.thing_id.nil? ||<br />

permission.thing_id == thing.id<br />

end<br />

end<br />

end<br />

end<br />

The Ability class’s initialize method defines how can? and cannot? will act. In<br />

this example, you iterate over all the users’ permissions and use the can? method to<br />

say that a user can perform a specific function. Users who shouldn’t be able to perform<br />

that function won’t have an entry in the permissions table for it. This is the<br />

whitelist authorization described at the beginning of the chapter.<br />

When you run bin/rspec spec/controllers/tickets_controller_spec.rb, you<br />

get this error:<br />

Failure/Error: get :new, :project_id => project.id<br />

undefined method 'permissions' for #<br />

189

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!