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.

184 CHAPTER 8 More authorization<br />

Define this factory now in a new file called factories/ticket_factory.rb. This file will be<br />

automatically loaded by the code in spec/support/factories.rb:<br />

Factory.define :ticket do |ticket|<br />

ticket.title "A ticket"<br />

ticket.description "A ticket, nothing more"<br />

ticket.user { |u| u.association(:user) }<br />

ticket.project { |p| p.association(:project) }<br />

end<br />

Here you set up some defaults for the title and description fields for a factoryprovided<br />

ticket, but you do something new with the user method. You pass a block<br />

and call the association method on the object returned from the block, and the user<br />

for this ticket becomes one user factory-created object. Nifty. You do the same thing<br />

for the project method, so you can create tickets using this factory and have them<br />

related to a project automatically if you want. For this spec, however, you override it.<br />

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

again, this test fails because the user can still access this action:<br />

TicketsController standard users cannot access a ticket for a project<br />

Failure/Error: response.should redirect_to(root_path)<br />

With this test failing correctly, you can work on restricting the access to only the projects<br />

the user has access to. Open app/controllers/tickets_controller.rb and remove the<br />

:except option from the authenticate_user! filter, so it goes from this<br />

before_filter :authenticate_user!, :except => [:index, :show]<br />

to this:<br />

before_filter :authenticate_user!<br />

Now users should always be asked to sign in before accessing the index and show<br />

actions for this controller, meaning that current_user will always return a User object.<br />

You can reference the current_user method in find_project and use the for<br />

method to limit the project find scope to only the projects to which that user has<br />

access. You can change the find_project method to the following example:<br />

def find_project<br />

@project = Project.for(current_user).find(params[:project_id])<br />

rescue ActiveRecord::RecordNotFound<br />

flash[:alert] = "The project you were looking for could not be found."<br />

redirect_to root_path<br />

end<br />

The rewritten find_project method will retrieve a Project only if the current_user<br />

has permission to view that project or is an admin. Otherwise, an ActiveRecord<br />

::RecordNotFound exception will be thrown and rescued here, showing users “The<br />

project you were looking for could not be found.”

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

Saved successfully!

Ooh no, something went wrong!