Reputation: 309
I'm trying to create a simple blogging application with 2 user levels: "writer" and "manager"
Writers belongs to managers, and managers can have many writers.
Writers can only see their own posts, but managers can see all the posts that their writers make.
Now my question is, how should I implement this type of system?
I'm pretty sure I should be using Devise to generate user authentication. But should I be generating separate models for each type of user (writer or model) or should I generate a roles table instead?
I don't know if that's specific enough; I spent the day racking my head over this with no solution in sight, so if you need to know more please let me know and I'll answer in the comments. Thanks in advance
Upvotes: 3
Views: 1872
Reputation: 389
I like the answer from hakunin, but I think he's missing something from the user model. I think there needs to be a "source" called out, otherwise there will be a "stack level too deep" error.
# Associates posts of all writers under this manager
has_many :writers_posts, :through => :writers, :class_name => 'Post', :source => :posts
Upvotes: 0
Reputation: 37357
Sounds like a simple user table with manager_id
.
create_table :users do |t|
# ...other columns...
t.integer :manager_id
end
class User < ActiveRecord::Base
# Returns all writers under this manager
has_many :writers, :class_name => 'User', :foreign_key => :manager_id
# Returns this writer's manager
belongs_to :manager, :class_name => 'User'
# Allows this user to be author of posts
has_many :posts
# Associates posts of all writers under this manager
has_many :writers_posts, :through => :writers, :class_name => 'Post'
# If user has no manager, she's a manager
def manager?
manager_id.nil?
end
# If user has a manager, she's a writer
def writer?
!manager?
end
end
This allows you to do the following things with your user.
if @user.manager?
@user.writers # => [<User>, <User>, ...]
@user.writers_posts # => [<Post>, <Post>, ...]
end
if @user.writer?
@user.manager # => <User>
end
This implementation determines whether a user is a manager or a writer simply by the presence of a manager. If a user has a manager, she must be a writer. Else, she's a manager. If this is not flexible enough you can add extra boolean columns specifying whether user is one, the other, or even both. Also note that this is simply a User
model that has both writer and manager methods. So you could call @writer.writers_posts
(which is not meant to be for a writer user), but you shouldn't.
Since all you have is a regular User
model, you can follow any Devise tutorial to setup authentication for it. Both writers and managers are just users who simply login.
As far as permissions and post visibility, it all comes down to being able to call the above methods on your current user.
if current_user.manager?
current_user.writers_posts.each do |post|
# display post
end
end
So frankly, CanCan is an overkill. All you need to do is add a few before_filter
and a few if current_user.manager?
conditions in your views. CanCan is more comprehensive, and on my experience it's too much in most apps.
Upvotes: 7
Reputation: 4566
Yes you should use devise and you should implement an admin role for the managers that has access to all the posts. https://github.com/plataformatec/devise/wiki/How-To:-Add-an-Admin-role provides instructions on how to do this.
Upvotes: 0
Reputation: 8744
Have a look at the following gem:
CanCan for authorization More info http://railscasts.com/episodes/192-authorization-with-cancan
For you user model you could have a column specifying the user role => manager or writer, and for each user you could have a manager_id column (when a user is manager you will put null here)
Edit: You should use Devise too, for authentication
Upvotes: 1