# Mixin application.rb problem

**URL:** <https://www.ruby-forum.com/t/mixin-application-rb-problem/147755>\
**Category:** Rails\
**Created:** [September 5, 2008, 3:40am UTC](https://www.ruby-forum.com/t/mixin-application-rb-problem/147755 "2008-09-05T03:40:35Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![pkoebbe](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ec9cab/32.png) [@pkoebbe](https://www.ruby-forum.com/u/pkoebbe)\
**Post date:** [September 5, 2008, 3:40am UTC](https://www.ruby-forum.com/t/mixin-application-rb-problem/147755/1 "2008-09-05T03:40:35Z")

</div>

Hello all.

I’m trying to implement my own role-based access scheme, and I’ve hit a  
bit of a snag. It may be that my idea is just plain wrong, and if so,  
I’d appreciate gentle instruction as to how to make it more sound.

My intent is to do something like

class MyController \< ApplicationController  
permit\_access(:admin)  
permit\_access(:normal\_user, :only =\> [:this, :that])

```
before_filter :require_access

def this
end

def that
end

def the_other
end

private

def require_access
    redirect_to error_path unless verify_access(@current_user)
end

```

end

The point of this endeavor is to more easily allow multiple roles to the  
same action. To that end, I created a module called RoleAccess that  
defines a permit\_access method and a verify\_access method. The idea is  
that I’d have a hash of controllers, actions, and roles that would be  
populated by permit\_access and inspected by verify\_access. The problem  
is that permit\_access is a class method and verify\_access is an instance  
method, so my module looks like

module RoleAccess  
module ClassMethods  
def permit\_access  
end  
end

```
module InstanceMethods
    def verify_access
    end
end

```

end

and I can’t figure out how to have a hash shared between  
ClassMethods::permit\_access and InstanceMethods::verify\_access. First,  
can this be done? If so, will someone please point me to some sample  
code that illustrates how to do it. I’ve been looking through various  
pieces of Rails source and scouring the internet, which has brought me  
to the point where I am, but I can’t quite get over the hump.

Peace,  
Phillip

---

<div class="post-metadata">

**Author:** ![pkoebbe](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ec9cab/32.png) [@pkoebbe](https://www.ruby-forum.com/u/pkoebbe)\
**Post date:** [September 5, 2008, 9:22am UTC](https://www.ruby-forum.com/t/mixin-application-rb-problem/147755/2 "2008-09-05T09:22:59Z")

</div>

On Sep 5, 2:40 am, Phillip K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> and I can’t figure out how to have a hash shared between  
> ClassMethods::permit\_access and InstanceMethods::verify\_access. First,  
> can this be done? If so, will someone please point me to some sample  
> code that illustrates how to do it. I’ve been looking through various  
> pieces of Rails source and scouring the internet, which has brought me  
> to the point where I am, but I can’t quite get over the hump.

Use your favourite class variable pattern and then do  
self.class.permitted\_actions or whatever you call it.

Fred

---

<div class="post-metadata">

**Author:** ![pkoebbe](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ec9cab/32.png) [@pkoebbe](https://www.ruby-forum.com/u/pkoebbe)\
**Post date:** [September 5, 2008, 4:46pm UTC](https://www.ruby-forum.com/t/mixin-application-rb-problem/147755/3 "2008-09-05T16:46:07Z")

</div>

On 5 Sep 2008, at 15:28, Phillip K. wrote:

> I should probably just write “Hello Fred”. Heh heh.
> 
> In application.rb, I have
> 
> class ApplicationController \< ActionController::Base  
> extend RoleAccess  
> init\_role\_access  
> At this point, no methods have yet been defined so it’s normal that  
> action\_methods is empty.

You also want to be careful with @@ - since you first define  
@@access\_map on ApplicationController, all controllers will share it  
(I wrote up some stuff on that not too long ago at  
[Fun with class variables - Space Vatican](http://www.spacevatican.org/2008/8/19/fun-with-class-variables))

one minor thing you could do would be to use the self.included hook on  
modules. This is called when the module is included so you could do just

include RoleAccess and do your init\_role\_access stuff from that hook

Fred

---

<div class="post-metadata">

**Author:** ![pkoebbe](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ec9cab/32.png) [@pkoebbe](https://www.ruby-forum.com/u/pkoebbe)\
**Post date:** [September 5, 2008, 4:28pm UTC](https://www.ruby-forum.com/t/mixin-application-rb-problem/147755/4 "2008-09-05T16:28:47Z")

</div>

> Use your favourite class variable pattern and then do  
> self.class.permitted\_actions or whatever you call it.
> 
> Fred

Hi Fred.

Funny enough, when I initially wrote “Hello all”, I mused to myself that  
I should probably just write “Hello Fred”. Heh heh.

Thanks for the instruction. You are a quite a help to a lot of people. I  
was watching the Ruby Hero awards the other day, and was thinking that  
you deserve one of those as well. Cheers to you!

Now, if I could pick your (or anyone else’s for that matter) brain a bit  
more, I’m having another problem with my access scheme. The original  
post was just generalities, so I’ll use specific code this time.

In application.rb, I have

class ApplicationController \< ActionController::Base  
extend RoleAccess  
init\_role\_access

protected

def require\_access  
redirect\_to person\_path unless verify\_access(@current\_person)  
end  
end

and in an actual controller, this

class SportsController \< ApplicationController  
permit\_access(:system\_administrator)  
permit\_access(:oranization\_administrator, [:index, :show, :update])  
permit\_access(:sport\_administrator, [:show, :update])

before\_filter :require\_logged\_in  
before\_filter :require\_access

…  
end

and finally, lib/role\_access.rb looks like

module RoleAccess  
def init\_role\_access  
include InstanceMethods  
extend ClassMethods  
@@access\_map ||= {}  
end

def self.access\_map  
@@access\_map  
end

module ClassMethods  
def permit\_access(\*args)  
access\_map = RoleAccess::access\_map

```
  #debugger
  controller = self.controller_name.to_sym

  # ********************************************
  # Problem with next line, see comment below
  all_actions = self.action_methods.collect { |action| action.to_sym 

```

}  
#\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

```
  options = args.last.is_a?(Hash) ? args.pop.symbolize_keys : {}
  by = args.first.is_a?(Array) ? args.first : [args.first]

  return if by.size.zero?

  if options.has_key?(:only)
    only = options[:only] || []
    to = all_actions.select { |a| only.include?(a) }
  elsif options.has_key?(:except)
    except = options[:except] || []
    to = all_actions.delete_if { |a| except.include?(a) }
  end

  to ||= all_actions

  return if to.size.zero?

  access_map[controller] = {} unless access_map.has_key?(controller)

  to.each do |action|
    access_map[controller][action] = [] unless 

```

access\_map[controller].has\_key?(action)

```
    by.each do |role|
      access_map[controller][action] << role unless
        access_map[controller][action].include?(role)
    end
  end
end # permit_access

```

end # module ClassMethods

module InstanceMethods  
protected

```
def verify_access(current_person)
  #debugger
  access_map = RoleAccess::access_map

  controller = controller_name.to_sym
  action = action_name.to_sym

  # if the controller is not explicitly listed, allow access
  return true unless access_map.has_key?(controller)

  # if the action is not explicitly listed, allow access
  return true unless access_map[controller].has_key?(action)

  # if we get here, the controller and action are both in 

```

access\_map…check to see  
# if the user can access the action  
roles = access\_map[:controller][:action]  
roles.each do |role|  
role\_method = “#{role}?”  
return true if current\_person.respond\_to?(role\_method) &&  
current\_person.send(role\_method)  
end

```
  return false
end # verify_access(current_person)

```

end # module InstanceMethods  
end

My intent, if it’s not clear, is to grant access to all the actions to  
system administrators, and access to selected actions to organization  
and sport administrators. It appears that sharing @@access\_map is now  
working, but the problem I am now having relates to the line indicated  
above:

all\_actions = self.action\_methods.collect { |action| action.to\_sym }

If I comment out all of the lines related to loading RoleAccess (as if  
it never existed) and go into script/console,  
SportController.action\_methods returns

> > SportsController.action\_methods  
> > =\> #\<Set: {“edit”, “delete”, “show”, “new”, “update”, “destroy”,  
> > “index”, “create”}\>

When trying to use RoleAccess and debugging the aforementioned line, I  
see that self is SportsController, yet action\_methods returns an empty  
set.

/Users/phillip/dev/projects/sports/sports\_dev/lib/role\_access.rb:17  
controller = self.controller\_name.to\_sym  
(rdb:27) p self  
SportsController  
(rdb:27) p self.respond\_to?(:action\_methods)  
true  
(rdb:27) p self.action\_methods  
#\<Set: {}\>  
(rdb:27) p SportsController.action\_methods  
#\<Set: {}\>  
(rdb:27)

So the long and short of it is when I don’t pass any actions in the call

permit\_access(:system\_administrator)

I want to grab all of the actions dynamically, but the fact that  
self.action\_methods is empty results in the system administrator being  
granted access to nothing.

Ideas?

Peace,  
Phillip

---

<div class="post-metadata">

**Author:** ![pkoebbe](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ec9cab/32.png) [@pkoebbe](https://www.ruby-forum.com/u/pkoebbe)\
**Post date:** [September 5, 2008, 5:46pm UTC](https://www.ruby-forum.com/t/mixin-application-rb-problem/147755/5 "2008-09-05T17:46:49Z")

</div>

Frederick C. wrote:

> At this point, no methods have yet been defined so it’s normal that  
> action\_methods is empty.

Well, hm. So they aren’t. Going to have to think about that one. I guess  
I need to look at the filter code some more to see how Rails gets around  
that.

> You also want to be careful with @@ - since you first define  
> @@access\_map on ApplicationController, all controllers will share it  
> (I wrote up some stuff on that not too long ago at  
> [Fun with class variables - Space Vatican](http://www.spacevatican.org/2008/8/19/fun-with-class-variables))

I thought of that, which is why I start by adding a key for the  
controller. This sort of thing is pretty new to me, so I might be  
missing something fundamental. If I just make it @access\_map, will each  
controller have its own? I’ll read your article and see if I understand  
better afterward.

> one minor thing you could do would be to use the self.included hook on  
> modules. This is called when the module is included so you could do just
> 
> include RoleAccess and do your init\_role\_access stuff from that hook

I tried do this different ways, but didn’t have any success. Part of my  
problem might be that I’m a bit confused by extend versus include. Based  
on what I’ve been reading, I thought that include was used to add  
methods to classes whereas extend added methods to instances (objects).  
The current form of

extend RoleAccess

is actually the reverse of what I thought I needed to have, so my grip  
on that one is apparently pretty weak. I’ll experiment with them and see  
if can’t get it cleaner.

> Fred

Thanks, Fred. Your insight and patience are very much appreciated.

Phillip

---

<div class="post-metadata">

**Author:** ![pkoebbe](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ec9cab/32.png) [@pkoebbe](https://www.ruby-forum.com/u/pkoebbe)\
**Post date:** [September 5, 2008, 6:01pm UTC](https://www.ruby-forum.com/t/mixin-application-rb-problem/147755/6 "2008-09-05T18:01:07Z")

</div>

On 5 Sep 2008, at 16:46, Phillip K. wrote:

> around  
> that.

Personally I’d do it when the filter runs, not ahead of time.

> missing something fundamental. If I just make it @access\_map, will
> 
> > include RoleAccess and do your init\_role\_access stuff from that hook
> 
> extend RoleAccess

Have a look at

> **[Ruby extend and include](http://blog.jayfields.com/2006/05/ruby-extend-and-include.html)**
>
> Module.include(module, ..) is commonly used to mix modules into classes and other modules. When a module is included the constants, methods...

or [Ruby Pattern: Extend through Include - Dan Manges's Blog](http://www.dcmanges.com/blog/27)

Fred

---

<div class="post-metadata">

**Author:** ![pkoebbe](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ec9cab/32.png) [@pkoebbe](https://www.ruby-forum.com/u/pkoebbe)\
**Post date:** [September 5, 2008, 7:43pm UTC](https://www.ruby-forum.com/t/mixin-application-rb-problem/147755/7 "2008-09-05T19:43:09Z")

</div>

Frederick C. wrote:

> Personally I’d do it when the filter runs, not ahead of time.

Thanks for saying that. It didn’t register at first what you were  
talking about, but it finally sank in and I followed that route. Wow, it  
really simplified things. I decided to take ApplicationController out of  
the picture completely and include RoleAccess in the specific  
controllers in which I need greater flexibility. Coupling that with your  
suggestion made it all cleaner. Now I can just include RoleAccess in  
SportsController and not worry about whether it’s a class method or an  
instance method. Since I am calling permit\_access and verify\_access from  
within require\_access, they are both instance methods. And that also  
solves the problem of action\_methods not being populated. The only  
difference is now I have to call

self.class.action\_methods

but that’s okay. The only downside, and it’s purely aesthetic, is not  
having the statements about access control at the top of the controller.  
When I come back to this later, or if someone else ever has to maintain  
this code (which might happen), it won’t be as obvious what’s going on.  
I suppose I could resort to that legacy construct we used to hear so  
much about. Oh what was it? A ‘comment’, I think.

> Have a look at  
> [Jay Fields' Thoughts: Ruby extend and include](http://blog.jayfields.com/2006/05/ruby-extend-and-include.html)  
> or [Ruby Pattern: Extend through Include - Dan Manges's Blog](http://www.dcmanges.com/blog/27)

Thanks again. Those resources helped. I’m going to have to put those in  
Evernote so I don’t forget about them.

So my module is much cleaner now, but I’m still confused by the access  
to the instance variable. I now have

module RoleAccess  
@access\_map ||= {}

def self.access\_map  
@access\_map  
end # access\_map

private

def permit\_access(\*args)  
access\_map = RoleAccess::access\_map  
…  
end

def verify\_access(current\_person = nil)  
access\_map = RoleAccess::access\_map  
…  
end  
end

I tried various ways to access @access\_map without having to use that  
ugly RoleAccess::access\_map, but nothing worked. I tried to apply what  
you wrote in the blog post you mentioned earlier, but I believe there  
are some differences between classes and modules in this regard. This  
approach does work, but I’d like it to be a bit cleaner.

Again, thanks for the help and patience. I really enjoy Ruby/Rails, but  
it’s taking me a bit of effort to wrap my head around a lot of it.

> Fred

Phillip
