Rails application with multiple roles - ruby-on-rails

I have a rails application with 2 roles, say admin and user. But the thing is, The admin doesn't use a backend like ActiveAdmin for example. I want both Admin and User to see the same views, but depending on the role, I restrict what they can see. I'm using Cancan, but since for example both admin and user can see the product page, I end up with many conditions inside the view and controller actions stating for example if this is an admin show that, if not then show that instead.
So I don't really think that this is the "Rails way". I end up with many repeated code, and code inside the views which doesn't really support the idea of keeping the logic away from the views.
So my question is, What's the best way to implement such a scenario with many roles but the same views.
Thank you.
I'm thinking of two options currently, but I don't like either. One is to redirect the admin to another view, but this way most of the view is the same hence it's not DRY at all.
Option 2 is to use the exact same view, but add many conditions in the view, so I end up with a huge complex view with code. I'm trying to find a way that keeps things DRY yet simple, and keeps the views code free.

You can have the admin module under seperate namespace and users as the default namespace. You can extract the common code under partials and use the same in both admin and user module.
This way you can separate the code for user and admin, and if sometime in future if you decide to go for a different views for admin and user. It won;t be much of a task.
Have controllers as
app/controllers/admin/articles ------ for admin users
app/controllers/articles ---- for normal users
and
views
app/views/admin/articles
app/views/articles
app/views/shared

There are different possible approaches. A variation of the 'decorator' pattern would come to mind as described here
It's some time I last read it, but I think the basic idea is to put the logic in the model or helpers. As soon as a user logs in and you can see if he is an admin or normal user you have methods that return the necessary html or text.
A more simple approach would be to just have two partials for everything. Either as Ross says in a separate admin namespace or even simpler (but more work if you later need to change that) just like _user_view_something.html.erb and _admin_view_something.html.erb.
Somewhat similar thoughts go into the DCI pattern. This Blog gives some nice overview how this could play into Rails. The article is more about permissions, but again the basic idea is to supplement the user object with the necessary functions.
So you have the basic "do_something" method which renders something or places some information in the view and replace it with the one that fits to the role the actual user has.

Related

How to set up Rails app that has different types of users?

If I want to build a Rails app that has two different types of users, let's say one type is called players and the other one is owners, what is the best and most efficient approach to modeling the app?
Things to take into account:
There should only be one Login, but different Registration forms that Owners/Players can use.
Owners can have access to a control panel but Players cannot.
Owners cannot share any of Players capabilities, but both need to be able to perform Login/Registration.
I am not using Devise, so please do not suggest it.
Different Approaches I've considered:
Using cancancan gem, but it does not really seem to meet my needs in the sense that I am not looking to create a user/admin hierarchical approach but rather a if you're a Player, then you can see these pages and perform these actions but Owners cannot and vice versa. Almost like splitting the app in two. cancancan seems that it would treat Owners as "Players with extra privileges", not different privileges entirely.
Creating separate models with separate login and registration forms, which seems like a disaster waiting to happen. One small mixup between a Players table and the Owners table, especially with the primary keys, and that will be a world of trouble where people could end up logging in to the wrong accounts.
Creating a polymorphic or has_one relation toward an Account model, which so far, seems like the best way to probably go about it. If I created a polymorphic Account model, I can store different types of Players/Owners, but how could I compare login credentials against all types?
I had been trying to find something on this matter regarding how to map this out and was surprised to not find an information on how to do this without using Devise. If anyone has any good links they can point me to that also address this matter (without Devise), please leave them in your answer! Thanks.
I'd suggest one User class with a type attribute that determines whether the user is a Player or an Owner (single table inheritance). This way you keep the registration logic in one place but can customize the forms depending on the user's class.
There must be alternatives to cancancan that help with what you want to do, or you can implement helpers yourself:
def can_access_control_panel?
current_user.is_a?(Owner)
end
You have to have a way to separate one user from another. One way is to add an attribute to the User table so you can call current_user.role and it will return "owner" or return "player".
I have used Pundit gem in the past. It lets you define which controller actions the current user is allowed to access. So as you create resources for your application, you can add a policy that specifies who is allowed to that given resource. This is the repo to the application.
This answer might help you.

Best practice when developing an RoR application

I am currently creating an application. It's relatively simple, lets say for now it only contains users & posts
What I am trying to do is display basically a blog with a new post form at the top in case the signed in user is admin.
I have two options:
I can use an index for posts and keep it all within the posts controller. I could add a form to the index.html.erb which checks for admin attributes.
However, I will most likely use the index functionality later on in other parts of the app.
Second option would be to create a static page called blog and render the form view and all posts.
Both should be possible, but what is the "rails way"? Or is there no best practice?
Controllers should be RESTful, and should be appropriately named for the resources they manipulate.
The index action of your PostsController should have one purpose ... providing appropriate information relating to all of the posts to its view. The exact output of this could change within the view depending on whether you're logged in as an admin or not, but essentially the role of that action should be restricted to that function.
I would advise you to take a look at the CanCan gem and think about how you could use that to authenticate users, providing appropriate page content to admins and normal users alike.

Tips for writing an admin interface in rails

I've been following this tutorial on creating a backend administration section for a rails 3 app.
I like the way it works, but the developer is required to manually generate namespaced controllers and models for each resource they want to administer in the backend.
RailsAdmin, in contrast, does not require you to do this, instead it detects which models you have in your app, and sets up admin sections for each one, without you having to generate any extra code.
Are there any resources out there, where I can learn to make my admin section work a little bit more like RailsAdmin? (I tried reading the RailsAdmin codebase but I get lost as there's quite a lot going on).
Ideally, I'd like my admin section to detect my application's models, and magically create admin pages for each one depending on that model's attributes. I'm certainly not asking anyone to write my code here, just looking for some tips on where to go in order to find out more about this sort of metaprogramming.

Ruby on Rails simple website layout

I'm learning RoR, I've read some tutorials (railstutorial for the first one),
but I've a problem to define the logic layout of the my first simple website.
The structure is:
When you go to mysite.com you see a welcome page with the signup form or the link for login.
If you signup or you login into the site, you are at mysite.com/dashboard and you see a list of your messages.
You can go to mysite.com/$username and you see a page with a form where you can write a message for the $username.
Stop. That's it. It's very simple, I know, but is for learning.
The problem is this: I'm new to MVC paradigm and I don't know how structure the logic layout of my app. Of course there'll two models: User and Message. But for controllers? And which functions in any controllers? Should I use scaffolding?
Please give me a help, I'm very confused.
Thank you.
Controllers are the logic for the data, so to login/sign-up is really validating/creating a user, if you need to view the users dash board, well that's a look up on the user data so he goes there as well.
The messages, that will be a separate controller that can create/view messages!
As others have pointed out, your controllers contain the logic for your code and invoke views based on that logic by rendering or redirecting to pages. You can define whatever actions you want in your controllers, and then use routes to map a particular URL to a controller action. That being said, Rails gets a lot easier if you "go with the flow" and make some simple assumptions about the actions that could happen. Both your users and your messages represent rows in their respective database tables. There's no much you can do to a row in a database table - you can Create it, Read it, Update it, or Delete it (CRUD). If you define your actions in terms of these four logical actions, Rails lets you generate some easy routes.
You can back into any URL schema that you want, but what you are describing is:
Read the messages that are for a user on the dashboard
Create a message for a user when you go to another page (mysite/username)
Each of these maps to a CRUD action that you should be defining in your controllers.
Agreed also with other advice to simply do a few more tutorials that will probably clear this up.
If you haven't already, read Getting Started with Rails. Look out for the discussion on MVC and scaffolding. Playing around with scaffolding can help you learn where things go and is a great place to start for beginners.
Also, I highly recommend this book: Agile Web Development with Rails. It is very hands on and an easy read.

Use nested controller or declarative authorization for admin action?

Say, I've an app with multiple models:posts, blogs, todos etc and I want an admin to edit, delete all users posts, blogs, todos, do I create a nested admin controller for each or use declarative authorization to setup an admin account that can edit/destroy the users, posts etc?
I understand this has no right answer, I'm just looking for the easiest and DRYest way to do it.
Thanks
Declaritive authorization is completely different thing from how you organize your admin situation. These are not different alternatives for the same problem. How you authorize actions or perform access control has nothing to do with whether your admin interface uses nested controllers and a different interface or uses the same interface as regular users with a few more buttons.
That said I'll take a stab at what I think you want to ask: Should your admin interface be the same as your user interface but with a few more buttons for admin actions?
My answer would be no even for the simplest of sites. Imagine having to clean spam from each and every post on your blog by having to visit each and every post.
Now imagine if you had a table of comments by date.
Which would you prefer?
Now if you decide your admins deserve a custom interface that suits their needs then you need to ask if it should be nested.
I'm not exactly a rails expert, but I thought this article was good: http://www.contextualdevelopment.com/articles/2008/nested-controllers-and-resources It points out some advantages of using the nested controller thing in the admin context you are describing.
If I understand right, in both cases you need an user with an admin role, right? So probably it's more about how to structure the controller. The nested controller setup imho is a bit cleaner because it saves a couple of conditions in the "main" controller. You simply put everything "admin" into the nested controller and everything else in the main controller.

Resources