-
Notifications
You must be signed in to change notification settings - Fork 41
Lesson use hydra access controls and cancan to decide whether to render a page
This Tutorial is known to work with hydra-head version 6.4.0.
Please update this wiki to reflect any other versions that have been tested.
- Use Hydra Access Controls and its built-in CanCan integration to decide whether to render a page
All of the methods described in this lesson are actually provided by a gem called CanCan. Hydra simply implements the ability for those CanCan methods to consult Hydra rightsMetadata to make decisions about access controls. The actual methods come from CanCan, so for more information you should consult the CanCan documentation.
Before starting this lesson, you need to have Controller, Views and Routes set up for Books. The easiest way to do this is by using the rails scaffold generator. See Lesson: Generate Rails Scaffolding for Creating and Editing Books in the Dive into Hydra tutorial for step-by-step instructions.
If you're using Rails 3, in app/controllers/books_controller.rb
find the lines that define the show
method and add authorize! :show, params[:id]
as the first thing the method does.
# GET /books/1
# GET /books/1.json
def show
authorize! :show, params[:id]
@book = Book.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @book }
end
end
Note to Rails 4 Users
Rails 4 generates slightly different code for the show
action:
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update, :destroy]
[...]
# GET /books/1
# GET /books/1.json
def show
end
[...]
private
# Use callbacks to share common setup or constraints between actions.
def set_book
@book = Book.find(params[:id])
end
[...]
Rewrite the show
action using the exact same code that is given above in the Rails 3 example, but edit the before_action
to look like this:
before_action :set_book, only: [:edit, :update, :destroy]
Here we've changed the before_action
so that it will not fire before our show requests.
Now that we've added CanCan's abilities to books_controller.rb
, we want to see if that controller will enforce the restrictions. To test this, we use the show
method on BooksController
which has the url of:
http://localhost:3000/books/changeme:1
The actual pid changeme:1
may differ in your application.
You'll note that this is different than the catalog controller path of /catalog/changeme:1
which you would get if you visited your book's show page when coming from a search result in Blacklight. This is because we've only attached CanCan's abilities to app/controllers/books_controller.rb
and not app/controllers/catalog_controller.rb
.
Now when you try to view a book's show
page using the BooksController
in the browser, you will get an error page (assuming you don't have read access to the book you're using).
CanCan::AccessDenied in BooksController#show
You are not authorized to access this page.
If you go into the rails console
and give yourself read access, then the page renders normally.
Likewise, you can add authorize! :edit, params[:id]
to the BooksController#edit
, BooksController#update
and BooksController#destroy
methods. Then save the file and see what happens in the browser. When you try to access the edit
page for an object that you don't have edit access to, you get an error, but if you go into the rails console
and give yourself edit access, then the page renders normally.
Instead of calling authorize!
in each of your methods, there's a one-line option you can use. At the top of app/controllers/books_controller.rb add a line that simply says load_and_authorize_resource
class BooksController < ApplicationController
load_and_authorize_resource
# GET /books
# GET /books.json
def index
@books = Book.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: @books }
end
end
[...]
end
This load_and_authorize_resource
method does two things for you. It loads a copy of the Book from Fedora and it runs authorize!
for you. So, if you're using this method you can also delete the lines that create @book
for you, for example:
@book = Book.find(params[:id])
If you're using load_and_authorize_resource
, it does that loading for you. This allows you to have less lines of code in your Controller.
Note: A drawback of using load_and_authorize_resource
is that it always loads a copy of the object from Fedora on every request. By contrast, calling authorize!
only reads the permissions metadata out of Solr, which is much faster than loading an object from Fedora. Either method works equally well. There is just the tradeoff: one method lets your application run faster while the other lets you have less lines of code in your Controller.
Go on to Lesson - Using Hydra Access Controls and CanCan to conditionally render part of a page or return to the Access Controls with Hydra tutorial.