Simply RESTful Controllers and Permissions

I’d like to incorporate RESTful resources in my app, and I’m having a
problem figuring out how to do it easily without namespaces. I’m
working in
edge rails, and I am creating an app for a school for which I’d like to
eventually have an API. Here’s the scenario:

  • The public can view a list of students as well as some information
    about each student
  • Each student can view more information than the public and edit
    some
    information about themselves
  • The teachers can view a more detailed list of all students and can
    edit all information, create and delete students
  • Teachers and students should be able to preview their changes on
    the
    “public” portion of the site while still logged in (meaning that the
    layouts
    have to be sensitive to whether or not they are logged in, and
    whether it
    should render in the “public” layout)

The public layout is completely different from the student layout, which
is
completely different from the teacher layout. In this case, a single
“show”
action (/students/1) would be rendered three different ways, with three
different layouts:

  • Public sees about 1/3rd of the student’s info using the public
    layout
  • Student sees about 2/3rds of the student’s info with links to
    update
    their own record using the student layout
  • Teacher sees all the student’s information and has links to update
    and destroy using the teacher layout

I have roughly 25 models to which similar logic will apply, and I may be
adding another role as well (like a mentor/advisor).

Initially, I had set this up with namespaced controllers and had a
public_controller, student_controller and teacher_controller, each with
their own actions. To DRY up and REST the app, I initially thought
about
creating a directory structure like:

/app/views/students
list.rhtml
show.rhtml
edit.rhtml
list
_teacher.rhtml
_student.rhtml
_public.rhtml
show
_teacher.rhtml
_student.rhtml
_public.rhtml
edit
_teacher.rhtml
_student.rhtml

I would then check the user’s roles and display the partial according to
their role. To complicate things, security is a big issue and making
sure
that no information ‘leaks’ to the public portion is essential.

Between the authentication, the layouts and the three different displays
I’ve lost the DRY principle altogether and it seems hard to test, since
I
can’t just check the action thats being rendered (I have to verify which
partial). Any other way I’ve thought of loses the RESTfulness and makes
an
API more complicated. When it comes to layouts, I’m completely stumped.

Does anyone have any advice or ideas about how to build a secure
3-user-tiered app in a RESTful, DRY way? Have any of you ever done
this?

I should mention that I was planning on using routes to distinguish the
different perspectives, like “:mode/:resource”. So that:

  • /teacher/students #= :controller=>‘students’, :action=>‘list’,
    :mode=>‘admin’
  • /student/students #= :controller=>‘students’, :action=>‘list’,
    :mode=>‘student’
  • /students #= :controller=>‘students’, :action=>‘list’,
    :mode=>‘public’

Thanks -

Jeff,

I decided that there are cases like this one where namespaces make
sense. It turns out that rails has built-in functionality to handle
resource name conflicts that we can use to deal with controller
namespaces.

If we have a model name Person and two controllers that operate on
this resource name PeopleController and Admin::PeopleController, we
can write the following routes in the routes.rb file:

map.resources :people
map.resources :people, :path_prefix => ‘admin’, :controller =>
‘admin/people’, :name_prefix => ‘admin_’

This will create two sets of named routes, one for each controller. We
just have to make sure that we use the right named route in the right
place:

admin_person_url(@person)
person_url(@person)

I have looked all over and I couldn’t find anywhere where this was
written about so I think I will make another post with more about
namespaces and REST. But I think this is how I will handle the
situation.

-Jake