# Simple authorization setup

**URL:** <https://discuss.rubyonrails.org/t/simple-authorization-setup/10220>\
**Category:** rubyonrails-talk\
**Created:** [March 14, 2007, 4:23am UTC](https://discuss.rubyonrails.org/t/simple-authorization-setup/10220 "2007-03-14T04:23:56Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![jim9](https://avatars.discourse-cdn.com/v4/letter/j/8491ac/32.png) [@jim9](https://discuss.rubyonrails.org/u/jim9)\
**Post date:** [March 14, 2007, 4:23am UTC](https://discuss.rubyonrails.org/t/simple-authorization-setup/10220/1 "2007-03-14T04:23:56Z")

</div>

I'm using single table inheritance to handle several types/roles of users within my application.

I want to be able to authorize certain actions based on user type.

I've seen Chad Fowler's recipe for users|roles|rights, but I like the simplicity of STI and don't really want to introduce any other tables/ models if I can help it.

Could anyone suggest some ideas for authorizing users by type within controllers?

Thanks.

---

<div class="post-metadata">

**Author:** ![Dale\_Cook](https://avatars.discourse-cdn.com/v4/letter/d/f19dbf/32.png) [@Dale\_Cook](https://discuss.rubyonrails.org/u/Dale_Cook)\
**Post date:** [March 14, 2007, 7:39am UTC](https://discuss.rubyonrails.org/t/simple-authorization-setup/10220/2 "2007-03-14T07:39:05Z")

</div>

Jim,

Don't know if this is what you're looking for but Rails supports a type of single inheritance that you could use Here's an example (this goes in the model file, so in this case user.rb):

&nbsp;&nbsp;&nbsp;&nbsp;class User \< ActiveRecord::Base

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def self.inheritance\_column &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'usertype' &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;class Visitor \< User; end &nbsp;&nbsp;&nbsp;&nbsp;class Editor \< User; end &nbsp;&nbsp;&nbsp;&nbsp;class Admin \< User; end

So, in your 'users' table you'd define a field (a varchar - make it as big as necessary) called 'usertype'. The above code defines a class called User which declares that it's inheritance\_column is 'usertype'. When I create users I don't create them from the User class, but rather from one of the subclasses (Visitor, Editor and Admin - you can define as many as you like).

So instead of saying something like

&nbsp;&nbsp;&nbsp;&nbsp;@this\_user = User.new(params[:user])

I'd do something like

&nbsp;&nbsp;&nbsp;&nbsp;@this\_user = Visitor.new(params[:user])

Which creates an entry in the 'users' table and puts 'Visitor' in the 'usertype' field. At some later point I could do something like

&nbsp;&nbsp;check\_user = User.find(params[:id])

&nbsp;&nbsp;if check\_user.usertype == 'Admin' &nbsp;&nbsp;&nbsp;&nbsp;etc... &nbsp;&nbsp;end

Notice here that I have used the User class again, rather than Visitor, that's because it's the parent class and I don't know what type of user it will return.

Hope this helps some.

Dale

---

<div class="post-metadata">

**Author:** ![Pierre-Alexandre\_Mey](https://avatars.discourse-cdn.com/v4/letter/p/b38774/32.png) [@Pierre-Alexandre\_Mey](https://discuss.rubyonrails.org/u/Pierre-Alexandre_Mey)\
**Post date:** [March 14, 2007, 8:26am UTC](https://discuss.rubyonrails.org/t/simple-authorization-setup/10220/3 "2007-03-14T08:26:58Z")

</div>

You could just add a row 'rights' in your user table? In your user model, you could add such methods:

def is\_admin? &nbsp;&nbsp;self.rights == 'admin' end

So, in your controllers, you'll be able to add easily before\_filter methods based on rights.

If you like STI, add an Admin\<User model and write methods like:

def self.find\_all(id) find(:all, :conditions =\> ['rights = admin']) end

and add a before\_save:

before\_save :admin\_rights

def admin\_rights &nbsp;&nbsp;self.rights = "admin" end

So, you'll be able to do Admin.create(:nom =\> 'pam') whithout think of the row 'rights' in your controller.

My $0.02.

---

<div class="post-metadata">

**Author:** ![Pierre-Alexandre\_Mey](https://avatars.discourse-cdn.com/v4/letter/p/b38774/32.png) [@Pierre-Alexandre\_Mey](https://discuss.rubyonrails.org/u/Pierre-Alexandre_Mey)\
**Post date:** [March 14, 2007, 4:03pm UTC](https://discuss.rubyonrails.org/t/simple-authorization-setup/10220/4 "2007-03-14T16:03:40Z")

</div>

> I have a proper loginsystem running and would like to enable/disable the restricted action on per user/controller base.

What do you mean by 'per user/controller base'?

If you just want to restrict access of some actions (may be in several controllers), just add in your controllers:

before\_filter :authorize, :only =\> [my\_restricted\_actions]

That is to say, it will call the method 'authorize' before each action in [my\_restricted\_actions].

The method authorize could be similar to (put it in application.rb):

def authorize if User.find(session[:user\_id]).rights == 'admin' &nbsp;&nbsp;return true else &nbsp;&nbsp;flash[:warning]="Hey! You're not admin!" &nbsp;&nbsp;redirect\_to :controller =\> "user", :action =\> "show" &nbsp;&nbsp;return false end end

If the User.find(session[:user\_id]) user is not an admin, the called method (destroy, update, ... whatever you want) won't be executed.

> I'm thinking about an extra field in de user model called areas, where 1 or more controllers are mentioned.

You don't have to think about controllers in your tables. Just add an extra row 'rights' in your users table and play with the snippet above.

> I would like to do this with as little tampering on the existing code as possible, to keep things tidy.

So I guess my method will suit to you 🙂

Hope that helps,

---

<div class="post-metadata">

**Author:** ![Tyler\_MacDonald](https://avatars.discourse-cdn.com/v4/letter/t/b5ac83/32.png) [@Tyler\_MacDonald](https://discuss.rubyonrails.org/u/Tyler_MacDonald)\
**Post date:** [March 14, 2007, 6:16pm UTC](https://discuss.rubyonrails.org/t/simple-authorization-setup/10220/5 "2007-03-14T18:16:47Z")

</div>

Well, if you are going to have multiple areas, you probably want a separate table to list them, then do something like

&nbsp;&nbsp;group = Group.find\_by\_name("Book") &nbsp;&nbsp;if users.groups.include?(group) &nbsp;&nbsp;&nbsp;&nbsp;# user can edit books &nbsp;&nbsp;&nbsp;&nbsp;...

&nbsp;&nbsp;Or, with the "do" block I was emailing about last night, it just becomes:

&nbsp;&nbsp;if users.groups.include?("Book") &nbsp;&nbsp;&nbsp;&nbsp;# ...

&nbsp;&nbsp;I hammered this out last night... I've got it to the point where a controller can say:

&nbsp;&nbsp;require\_group :Admin

&nbsp;&nbsp;, etc, to restrict access. it's not ready for "release" yet, but if anybody wants to take a look at the models/migrations/authenticatedSystem, send me an email off-list.

&nbsp;&nbsp;Cheers, &nbsp;&nbsp;&nbsp;&nbsp;Tyler

---

<div class="post-metadata">

**Author:** ![Pierre-Alexandre\_Mey](https://avatars.discourse-cdn.com/v4/letter/p/b38774/32.png) [@Pierre-Alexandre\_Mey](https://discuss.rubyonrails.org/u/Pierre-Alexandre_Mey)\
**Post date:** [March 14, 2007, 6:58pm UTC](https://discuss.rubyonrails.org/t/simple-authorization-setup/10220/6 "2007-03-14T18:58:54Z")

</div>

> That the, password protected, editing can be enabled for the users per controller (well model actually). e.g.
> 
> User: mark Areas: Book CD
> 
> So in this case the user mark is allowed to edit the models Book and CD

Ok, it's clear now. You want to define areas in you app in which you can manage rights for your users.

> Looks clear! I'll play with it. Still wondering how ik can restrict this to a specific model. Use something like this maybe?
> 
> .... User.find(session[:user\_id]).rights == 'modelname\_admin'
> 
> Use the model name for the 'rights' value.

You could handle your rights like this. But what happens if your modelname change tomorrows? By the way, mark is admin of the book shop AND the CD shop. How will you handle it?

> Hmm ... maybe just check for the value book (in the field area) with the method "authorize" and then it's based on the available models.

I suggest you to create a table for your areas:

create\_table "admin\_areas", :force =\> true do |t| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.column "name", :string &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.column "user\_id", :integer end

class User \< ActiveRecord::Base has\_many :admin\_areas

def is\_admin\_for?(area) &nbsp;&nbsp;AdminArea.find\_by\_name\_and\_user\_id(area,self.id) end

end

The second method return true if it finds something or nil if it doesn't.

Assuming you have @area='book' in your controller book\_controller.rb, you can define in your application.rb:

def authorize if User.find(session[:user\_id]).is\_admin\_for?(@area) &nbsp;&nbsp;return true else &nbsp;&nbsp;flash[:warning]="Hey! You're not admin for area #{@area}!" &nbsp;&nbsp;redirect\_to :controller =\> "user", :action =\> "show" &nbsp;&nbsp;return false end end

> It definitely does.

Cool 🙂

---

<div class="post-metadata">

**Author:** ![Pierre-Alexandre\_Mey](https://avatars.discourse-cdn.com/v4/letter/p/b38774/32.png) [@Pierre-Alexandre\_Mey](https://discuss.rubyonrails.org/u/Pierre-Alexandre_Mey)\
**Post date:** [March 14, 2007, 7:06pm UTC](https://discuss.rubyonrails.org/t/simple-authorization-setup/10220/7 "2007-03-14T19:06:16Z")

</div>

> &nbsp;&nbsp;group = Group.find\_by\_name("Book") &nbsp;&nbsp;if users.groups.include?(group) &nbsp;&nbsp;&nbsp;&nbsp;# user can edit books &nbsp;&nbsp;&nbsp;&nbsp;... &nbsp;&nbsp;Or, with the "do" block I was emailing about last night, it just becomes:
> 
> &nbsp;&nbsp;if users.groups.include?("Book") &nbsp;&nbsp;&nbsp;&nbsp;# ...

The point is, what if the variable 'users' change one day? Or if you want to change 'Book' to 'bookshelf'? The code is much cleaner and easier to improve if you don't put such logic in each method in your controllers.

> &nbsp;&nbsp;I hammered this out last night... I've got it to the point where a controller can say:
> 
> &nbsp;&nbsp;require\_group :Admin
> 
> &nbsp;&nbsp;, etc, to restrict access. it's not ready for "release" yet, but if anybody wants to take a look at the models/migrations/authenticatedSystem, send me an email off-list.

Great! I'm gonna send you an email right now 🙂

---

<div class="post-metadata">

**Author:** ![Tyler\_MacDonald](https://avatars.discourse-cdn.com/v4/letter/t/b5ac83/32.png) [@Tyler\_MacDonald](https://discuss.rubyonrails.org/u/Tyler_MacDonald)\
**Post date:** [March 14, 2007, 8:30pm UTC](https://discuss.rubyonrails.org/t/simple-authorization-setup/10220/8 "2007-03-14T20:30:19Z")

</div>

Yep, it's in my authenticated\_system.rb, which is included by the application controller.

&nbsp;&nbsp;Cheers, &nbsp;&nbsp;&nbsp;&nbsp;Tyler
