resources_controller under the hood magic

0 views
Skip to first unread message

satynos

unread,
Dec 15, 2008, 12:17:37 PM12/15/08
to resources_controller
Ian:

I started implementing resources_controller in our project and so far
its excellent, particularly the deep nesting support. Now we need to
introduce Authentication and Authorization into the picture. We want
to implement Authentication using the restful_authentication and have
no problems.

But when it comes to Authorization, we need to hook into the filters
(before_filter, around_filter stuff). After reviewing your code, it
looks like you are using before_filter only to load the enclosing
resources and loading the current resource within the controller
action. We could patch in your code particularly the actions.rb and
get away with the Authorization setup. But in order to keep up to date
with your code, we are trying not to touch your code but apply the
authorization with the filters.

For this we would like to get a grasp around the code implementation
(under the hood magic), particularly I want to know how you are
loading the enclosing resources and the current resource. I got lost
in the resource_service and how you are recognizing the routes. I
would appreciate it if you could briefly explain the code flow at the
earliest of your convenience.

Thanks in advance.

Jason Lee

unread,
Dec 15, 2008, 5:40:12 PM12/15/08
to resources_controller
Hi Satynos,

I can't help you with the under-the-hood magic, but I can suggest that
you might want to use what Ian calls the /account pattern.

Take a look at examples "3" and "4 and a bit" at
http://plugins.ardes.com/doc/resources_controller/classes/Ardes/ResourcesController.html
So, for example consider an app where users are authorized to create/
edit/delete their own posts and everyone can view all posts.

class User < ActiveRecord::Base
has_many :posts, :dependent => :destroy
end

class Post < ActiveRecord::Base
belongs_to :user
end

class ApplicationController < ActionController::Base
map_resource :user, :singleton => true, :class => User, :find
=> :current_user # current_user method from restful_authentication
end

# routes.rb

## everything under /user is scoped to current_user (e.g.
@user.posts )
map.resource :user do |user|
user.resources :posts
end

## public view only under /posts , using new rails 2.2.2 :only option
map resources :posts, :only => [:show, :index ]

Roles, Memberships, Friendships, private messages etc. can all be
controlled with the /account pattern either by deeply nesting under
the top level singleton resource /user or by creating new top level
resources which have custom R_C finders that use current_user.


Jason.

satynos

unread,
Dec 17, 2008, 8:36:22 AM12/17/08
to resources_controller
Jason:

Thanks for your feedback and sorry for the dealy in my response.

Unfortunately Examples 3 and 4 that you quoted doesn't help in my
situation. Basically I have to run my Authorization (not
Authentication, ofcourse Authorization indirectly depends on
Authentication) code after loading the resource (current resource)
based on checking the current users credentials. But the way that
resources_controller code is setup right now, there is no way, unless
I hack the actions.rb file and include my code within those functions
(methods to be precise) or move the load_resource(s) calls from within
those functions to the before filter and append my authorization
filters. Personally I think these load_resource(s) calls are a good
candidate to move into before filters anyway.

Also I am currently working on refactoring the code, so that the
changes I make in those files will reflect immediately if I set the
config.reload_plugins = true (very useful in development mode) instead
of rebooting the server. Once I am finished making these changes, I
will submit my findings.

Once again thanks for the feedback.

BTW: After fidling through the code and using some debugging, finally
I figured out the order of execution of code, particularly in loading
the resources (both enclosing and current) and Andres did an excellent
job which sets resources_controller at par with make_resouceful and
resource_controller plugins. I am still trying to understand how
Andres is setting the paths (automatically including the enclosing
resources in the path) though from resource_path and resources_path.

-Satynos



On Dec 15, 5:40 pm, Jason Lee <jls...@gmail.com> wrote:
> Hi Satynos,
>
> I can't help you with the under-the-hood magic, but I can suggest that
> you might want to use what Ian calls the /account pattern.
>
> Take a look at examples "3" and "4 and a bit" athttp://plugins.ardes.com/doc/resources_controller/classes/Ardes/Resou...

Chris Hapgood

unread,
Dec 17, 2008, 10:00:42 AM12/17/08
to resources_...@googlegroups.com
I think that 'hacking" actions.rb is SOP (standard operating
procedure). The default actions are not really suitable for anything
but the most basic applications so I would suggest you not hesitate to
override them. Once you've taken that step, you can easily write your
own before/around filters to manage the resource(s) finding and then
your auth code. Ian put work into RC to get the resource
identification filter to be flexible -you can move it around at will
to ensure it comes before your own filters.

Incidentally, Satynos, I'm in exactly the same situation as you -my
custom authorization plugin (wicked good -ask me about it if you're
interested) usually needs the resource to evaluate the authorization
expression. But depending on the action, it may need the enclosing
resource or associated resources instead of, or in addition to, the
basic resource. So drying up the auth code into a before filter isn't
very realistic for me except in the simplest cases. Once I gave up on
moving the authorization code into a before filter, moving the finder
code into a before filter lost much of its appeal as well. And the
finder code has at least three variants in the canonical Rails
controller:

1. Index (find existing resource collection from class or enclosing
resource association)
2. new/create (create a new single resource)
3. edit/update/delete (find an existing single resource)

In a nutshell, I think there are too many variants of finder code (and
its placement) to warrant putting it into a core before filter.
Enclosing resources are easier -the finder only ever needs to find an
existing, single, resource.

-Chris
Chris Hapgood
cc...@hapgoods.com




satynos

unread,
Dec 17, 2008, 3:18:52 PM12/17/08
to resources_controller
Chris:

"I think that 'hacking" actions.rb is SOP (standard operating
procedure). The default actions are not really suitable for
anything
but the most basic applications so I would suggest you not hesitate
to
override them. Once you've taken that step, you can easily write
your
own before/around filters to manage the resource(s) finding and
then
your auth code. Ian put work into RC to get the resource
identification filter to be flexible -you can move it around at
will
to ensure it comes before your own filters."

Thats exactly what I did, for the time being I just commented out the
find_resource, find_resources and new_resource code and moved it into
the before_filter in the resources_controller_for method. My
before_filter chain after the changes:

before_filter(:load_enclosing_resources, when_options) unless
load_enclosing_resources_filter_exists?
before_filter :load_resources, :only => [:index]
before_filter :load_resource, :only =>
[:show, :edit, :update, :destroy]
before_filter :build_resource, :only => [:new, :create]

The other option I was thinking is to create my own actions module and
pass it to the resources_controller_for and so that my module will be
used instead of built-in actions.rb file. Either way works fine.

"Incidentally, Satynos, I'm in exactly the same situation as you -
my
custom authorization plugin (wicked good -ask me about it if you're
interested) usually needs the resource to evaluate the
authorization
expression. But depending on the action, it may need the enclosing
resource or associated resources instead of, or in addition to, the
basic resource. So drying up the auth code into a before filter
isn't
very realistic for me except in the simplest cases. Once I gave up
on
moving the authorization code into a before filter, moving the
finder
code into a before filter lost much of its appeal as well. And the
finder code has at least three variants in the canonical Rails
controller:

1. Index (find existing resource collection from class or
enclosing
resource association)
2. new/create (create a new single resource)
3. edit/update/delete (find an existing single resource)"

I am not quite sure what you mean by several variants of finders, I
think (unless I am missing something) finding the resource should be
either from its own Model or through the enclosed resources if the
resouce is nested. For instance if I have the URL like users/1/
articles/1/comments, comments will be loaded through the following:

@user = User.find
@article = @user.articles.find
@comments = @article.comments

In other instance if the URL is users/1 then there is not enclosed
resource and the user will be loaded @user = User.find

For either situations, resources_controller is handling by itself. At
this moment all I wanted is to run the load_enclosed_resources and
load_resource taken care in the before filter so that I can either use
around filter for authorization (after these two filters are taken
place) or just use before_filter to either redirect the user to login
if he has no logged in yet or thow access_denied if denied or just
return true for the rails to proceed normally.


"Incidentally, Satynos, I'm in exactly the same situation as you -
my
custom authorization plugin (wicked good -ask me about it if you're
interested) usually needs the resource to evaluate the
authorization
expression. "

I would like to take a peek at your code which might save me some time
if it is similar to what I have in my mind.

Following is what I have in mind:
User has_many :roles
User has_many :permission :through => :roles
(This setup gives me permission management through web interface)

Then use either one of the following variants in the before or after
filters or may be just inline in the method of my actions module:

Checking permission Proxy through User:
current_user.can_view?(resource)
current_user.can_create?(resource)
current_user.can_edit?(resource)
current_user.can_delete?(resource)

Checking permission Directly on Resource: (the above indirectly calls
these)
resource.viewable_by?(current_user)
resource.creatable_by?(current_user),
resource.editable_by?(current_user) and
resource.deletable_by?(current_user)

And in the Resource
def viewable_by?(current_user)
if current_user.has_perm?('View Content') || self.user_id ==
current_user.id
return true
else
return false
end

But I would certainly love to take a peek at your code, if that is ok
with you.

Thanks in advance.
-Satynos







Also I would like to utililze permission based system that can be
altered through web UI so that I can give whatever permission I want
to a particular role.
> c...@hapgoods.com

Chris Hapgood

unread,
Dec 17, 2008, 3:22:41 PM12/17/08
to resources_...@googlegroups.com
It is easy to create your own actions module (I keep mine in /lib) and
configure RC to use it -I would highly recommend that approach versus
modifying the standard actions file.

On 17 Dec 2008, at 15:18, satynos wrote:

> The other option I was thinking is to create my own actions module and
> pass it to the resources_controller_for and so that my module will be
> used instead of built-in actions.rb file. Either way works fine.

Chris Hapgood
cc...@hapgoods.com


Chris Hapgood

unread,
Dec 17, 2008, 3:34:40 PM12/17/08
to resources_...@googlegroups.com
"Finders" was probably not the best choice of words. My intent was to
point out that there are three cases of obtaining the resource in a
standard Rails controller:

find_resource (edit, update, destroy)
find_resources (index)
new_resource (new, create)

Determining which one of the above three to use in a before filter is
kinda ugly since your conditional is stuck with reflecting on the
controller action anyway. And any additional actions would need
special treatment. In the general case, It's best to just leave that
code in the individual actions. I gather in your case you want to
evaluate authorization in a before filter so you are stuck with
finding the resource in a before filter.

-Chris

On 17 Dec 2008, at 15:18, satynos wrote:

> I am not quite sure what you mean by several variants of finders, I
> think (unless I am missing something) finding the resource should be
> either from its own Model or through the enclosed resources if the
> resouce is nested. For instance if I have the URL like users/1/
> articles/1/comments, comments will be loaded through the following:

Chris Hapgood
cc...@hapgoods.com


satynos

unread,
Dec 17, 2008, 3:55:02 PM12/17/08
to resources_controller
Would you be kind enough to share your idea on making the
authorzation.

"Incidentally, Satynos, I'm in exactly the same situation as you -
my
custom authorization plugin (wicked good -ask me about it if you're
interested)"

How is my approach that I posted? It certainly needs lot of work
especially defining all the authorizable methods in each model. Also
when presenting the permissions in the permission section I have to
initiate all the models for permissions method to get all the
available permission system wide. I am thinking of making a plugin for
the time being I am calling acts_as_authorizable and define some
default authorizable methods and one can pass the list of permission
to that method, may be like this?

class SomeModel < ActiveRecord::Base
acts_as_authorizable :with_permission => ['create some model',
''view some model', 'edit own some model', ...] do |some_model|
(define methods that needs to be added to the instances)
def creatable_by?(current_user)
logic goes her
end #end of creatable_by? method
end #end of do
end # end of class SomeModel

BTW: How can I automatically get those > in the reply?

-Satynos
> c...@hapgoods.com
Reply all
Reply to author
Forward
0 new messages