Authorization to allow user to edit certain records (his own)

81 views
Skip to first unread message

Mike Blyth

unread,
Aug 6, 2012, 3:55:06 AM8/6/12
to actives...@googlegroups.com
I know there must be a simple solution for this but I haven't found it. What I have is a directory of people. I want to authorize each person to edit her own record but no others. Thus authorization depends on a comparison with user and database record.

I have tried this in the controller:

    def update_authorized?(record=nil)
      is_member = (record.is_a? Member)
      same_id = is_member ? current_user.id == record.id : false
      ok = is_member && same_id
      return ok
    end

(the logic is broken up just so I can grasp it better). This almost works but leaves two problems.

First, in the authorized record the associated record fields in the list view are blocked from inline editing, though all the other fields are editable.  For example, the user can edit his own name but not his nationality, because the latter is an associated field with a drop-down selector.

Second, the Edit action link at the end of the authorized is disabled, along with those of all the unauthorized records. That seems to be because the authorization method only returns true when a record is present; if I change the last statement to return return ok || !is_member then the Edit links for all the records become active again.

The documentation refers to using authorization methods in the model in order to control the action links, but the model does not have session available, so I'm not sure how to solve the problem. Thanks for any help!

Mike Blyth

unread,
Aug 6, 2012, 4:00:55 AM8/6/12
to actives...@googlegroups.com
Well, I just solved the first problem (user can't edit associated fields). It had nothing to do with AS but was another manifestation of having the pre-compiled assets visible in public/assets during testing. Removed that folder and it works fine. That just leaves the second problem, having the edit link (and action) available on the user's own record but not others.

Mike Blyth

unread,
Aug 6, 2012, 4:44:00 AM8/6/12
to actives...@googlegroups.com
I'm going to convert this project to use CanCan, which I should have used in the first place, but I'm still interested in knowing how I would solve the problem without CanCan.

Hernan Astudillo

unread,
Aug 6, 2012, 6:08:43 PM8/6/12
to actives...@googlegroups.com
without CanCan, you should use the Model way:

def authorized_for_update?
  return self.id == current_user.id
end

with CanCan:

can :update, Member, :id => current_user.id



On Mon, Aug 6, 2012 at 4:44 AM, Mike Blyth <mike....@sim.org> wrote:
I'm going to convert this project to use CanCan, which I should have used in the first place, but I'm still interested in knowing how I would solve the problem without CanCan.

--
You received this message because you are subscribed to the Google Groups "ActiveScaffold : Ruby on Rails plugin" group.
To view this discussion on the web visit https://groups.google.com/d/msg/activescaffold/-/kuCaT4fnVysJ.

To post to this group, send email to actives...@googlegroups.com.
To unsubscribe from this group, send email to activescaffol...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/activescaffold?hl=en.

Ed W

unread,
Aug 7, 2012, 7:27:00 AM8/7/12
to actives...@googlegroups.com
On 06/08/2012 23:08, Hernan Astudillo wrote:
without CanCan, you should use the Model way:

def authorized_for_update?
  return self.id == current_user.id
end


I think the key inspiration is that you need to cheat and pass around a non model (global/singleton) variable that reveals the "current user".  With that you can then do everything else at the model level

Ed
Message has been deleted

Hernan Astudillo

unread,
Aug 7, 2012, 10:52:24 AM8/7/12
to actives...@googlegroups.com
But AS already do this: current_user is accessible across all models, controllers and views. Devise and CanCan share the same trick.

--
You received this message because you are subscribed to the Google Groups "ActiveScaffold : Ruby on Rails plugin" group.

Mike Blyth

unread,
Aug 12, 2012, 4:41:05 AM8/12/12
to actives...@googlegroups.com
OK, I read now about @current_user in AS. But my model is not seeing it. I have set config.security.current_user_method = :current_user just to be sure, even though it is the default, and the current_user is being called and returning the right user (within application_controller), but @current_user is nil within my model. What am I missing?

Sergio Cambra

unread,
Aug 13, 2012, 2:22:09 AM8/13/12
to actives...@googlegroups.com
There is no @current_user in AS, you can call current_user method

On Domingo, 12 de agosto de 2012 01:41:05 Mike Blyth escribió:
> OK, I read now about @current_user in AS. But my model is not seeing it. I
> have set config.security.current_user_method = :current_user just to be
> sure, even though it is the default, and the current_user is being called
> and returning the right user (within application_controller), but
> @current_user is nil within my model. What am I missing?
>
> On Tuesday, 7 August 2012 15:52:24 UTC+1, Hernán Astudillo wrote:
> > But AS already do this: current_user is accessible across all models,
> > controllers and views. Devise and CanCan share the same trick.
> >
> > On Tue, Aug 7, 2012 at 7:27 AM, Ed W <li...@wildgooses.com
<javascript:>>wrote:

Mike Blyth

unread,
Aug 13, 2012, 5:31:28 AM8/13/12
to actives...@googlegroups.com
OK, the problem was that I was still including the :current_user method itself in the model, through "include SessionHelper", causing an error about not finding the session when I used that method. Removed the include and now the AS-derived current_user method works.

The wiki documentation for Security shows

    def list_authorized?
         @current_user.some_boolean_property
    end

as the way to set the authorization in the controller. Should this be changed?

Mike Blyth

unread,
Aug 13, 2012, 5:57:43 AM8/13/12
to actives...@googlegroups.com
Is it possible to use the AS authorization and CanCan in the same application? I thought it was, but I can't find a way to do so. Even if I use skip_authorization_check in the controller, it still uses the CanCan authorizations exclusively, ignoring those of AS. So perhaps you have to choose one or the other?


On Monday, August 13, 2012 7:22:09 AM UTC+1, Sergio Cambra wrote:

Sergio Cambra

unread,
Aug 13, 2012, 6:26:19 AM8/13/12
to actives...@googlegroups.com
Yes, if you install CanCan bridge will be enabled and you will only be able to
use CanCan

Sergio Cambra

unread,
Aug 13, 2012, 6:27:28 AM8/13/12
to actives...@googlegroups.com
On Lunes, 13 de agosto de 2012 02:31:28 Mike Blyth escribió:
> OK, the problem was that I was still including the :current_user method
> itself in the model, through "include SessionHelper", causing an error
> about not finding the session when I used that method. Removed the include
> and now the AS-derived current_user method works.
>
> The wiki documentation for Security shows
>
> def list_authorized?
> @current_user.some_boolean_property
> end
>
> as the way to set the authorization in the controller. Should this be
> changed?
>

No, documentation explain how to add authorization in the controller and
model. It's better to set in the model IMHO but sometimes you can need to use
some session info and you can need to use controller

Mike Blyth

unread,
Aug 13, 2012, 6:42:11 AM8/13/12
to actives...@googlegroups.com
But you said that @current_user is incorrect, that current_user should be used, while the example shows @current_user.

Mike Blyth

unread,
Aug 13, 2012, 6:46:05 AM8/13/12
to actives...@googlegroups.com
Sorry I'm so confused :-( 

I started to update the Wiki to reflect that "if you install CanCan bridge will be enabled and you will only be able to
use CanCan," but I see on the CanCan page "delegates to default AS security in case CanCan says 'no'," which sounds as if AS security is used on top of CanCan. That is not what I found. So, is that statement in the Wiki incorrect and to be removed?

Sergio Cambra

unread,
Aug 13, 2012, 7:06:07 AM8/13/12
to actives...@googlegroups.com
I never used CanCan bridge, so I don't know if you are getting the expected
behavior, I only added CanCan bridge which was provided in a pull request. I
thought CanCan replaced default AS security. Can you wait someone confirm the
expected behaviour?

Sergio Cambra

unread,
Aug 13, 2012, 7:11:39 AM8/13/12
to actives...@googlegroups.com
Sorry, I didn't saw the @, I thought you were talking about using model
security instead of controller security. @current_user is incorrect in the
model, because AS doesn't set @current_user, only adds current_user method to
get the current user from the controller using the method you set with
config.security.current_user_method

In the controller you can use whatever authentication defines. If your
authentication code defines current_user method and set @current_user, you can
use both in the controller.

So, yes, change @current_user with current_user in the example, because it can
be confusing
Reply all
Reply to author
Forward
0 new messages