How to add a new role in Spree? - ruby-on-rails

I currently have two roles in my system, the defaults, 'User' and 'Admin'.
I would like to add a new role called 'Supplier'.
At the moment the supplier role needs to be the same as a normal user. I have 'frontend' profile edit page. The only difference between the user and supplier is that the supplier has a few more fields they can fill out. I plan on permissioning these extra fields by checking their role against spree_has_role?('supplier')
So what's the best way of adding the role to the database (do I add this to an initializer)?
How do I then add permissions to this role to be the same as the 'user' role?
At some point I'll want to extend the permissions, but one thing at a time.
I can't find any clear guide that shows how to do any of this (or at least anything that's been updated in the last year or two). I appreciate if any one can help me out with some instructions / examples.
P.s. I'm using Spree 2.2 Stable with Devise Auth.

Regular users have not any particular permission as you can see into the ability model (https://github.com/spree/spree/blob/master/core/app/models/spree/ability.rb) . You can just create the role in the database from the console using:
Spree::Role.create(name: 'Supplier')
If you need to be sure you have this role in the database and you want to put it into an initializer be sure to check if the role is not yet been created. You can use something like:
Spree::Role.find_or_create_by_name('Supplier')
At this point you can just use in the profile edit view something like:
<% if #user.has_spree_role?('Supplier') %>
...
additional fields here
...
<% end %>

Related

How to create multiple roles for single user in ruby on rails?

I am trying to create a web application using ruby on rails. In this application a user has multiple roles like
role1 = teacher
role2 = student
role3 = staff
But the thing is a user can switch between these roles by changing account settings in the application.
eg :
Student can also change his role as teacher and then they can teach someothers
When they change the role the pages, timeline, homepage everything should be display according to their current role.
How can i model the database for this and how can i perform the associations for this ?
I am new to ruby on rails so please help & thanks in advance!
Ofcourse! you can keep track of current user and then you assign user role when they switch.
If not you can also use rolify gem to add or remove roles and [cancan][3] gem for authorization.
You could keep a list of user roles and also track something called a current role.

Rails_admin exclude fields by authorization

I have model called Person. It has two child models Admin and Owner.
I have created rails_admin dashboard with multiple models with associations.
I have added devise to Person, that is why Admin and Owner can log in to my dashboard.
I have added authorization with cancan and defined their abilities. Admin can manage everything while Owner can manage his own data.
Now here is the problem. When Owner logs in and tries to edit himself, he need to write his own password and that is good.
However, when admin logs in and tries to edit Owner, it asks to write password of Owner.
How to exclude some fileds in actions, depending on who is now changing it?
I though to use current_person which is logged in mby devise, but how to get it when my rails_admin do /* my code */ end is placed inside my models code?
Here is one way to hide password field so only user editing his/her record can see it.
edit do
include_all_fields
[:password, :password_confirmation].each do |f|
field f do
visible do
bindings[:object].id == bindings[:view].current_user.id
end
end
end
end
You could create a custom action to reset password restricted only to Admins.

Modelling multiple types of users with Devise and Rails 4

I have 3 types of "users"
Shop
Provider
Customer
The last 2 users will have similar attributes such as
First Name
Last Name
and so on
And the Shop user type will have the most contrast between types.
As far as behaviours they will all be quite different, although Provider and Shop will inherent many of customer behaviours.
It seems the behaviours can be dealt with CanCan as I've researched.
I'm now attempting to how I should authenticate these types.
I have looked at the STI model but I couldn't grasp where I would these extra attributes.
My mental model is as follower:
User is a table and model
The types are abstract models that inherit from this.
So I'm wondering, how do I add attributes such as Business address for just the Shop type?
Or is it that the User Table has a column called Type and that type is associated with these type tables? And within the type tables are the extra attributes?
Don't even bother bringing Devise into this; Devise is for authentication not authorization. Authentication is determining whether or not someone who visits your site is who you think they are, like logging in. Authorization is deciding whether or not a user is allowed to perform some sort of action, like creating a new post.
What you want to do is have some sort of system that assigns a normal user your three different types; CanCan will do something like that. One way to do this on your own is using a permissions number based system. Let's say normal users have permissions level at 100, shop has a level at 50, and provider at 25. Using this system you can determine what actions a user can perform without having to make separate models, which will make your schema unnecessarily complicated. Here's an example of how this would work with say the UserController:
def show
if current_user.permissions == 100
render "customer_show"
elsif current_user.permissions == 50
render "shop_show"
else
render "provider_show"
end
end
The easiest way to do this is to add a column to the user's table called permissions that defaults to say 100 when a new row is created. Here's what that migration would look like:
def change
add_column :users, :permissions, :integer, default: 100
end
As for authenticating, don't worry about it. Let devise do it's thing; every user, no matter what type, will login and sign up in the same way, maybe just having separate forms for each that has a hidden field to set the permissions level for that specific kind of user.
I know I'm late to the party but I'm putting this out for future SO searchers. You CAN authorize actions with Devise. If you have devise models for 'buyer' & 'seller' you can add 'buyer_signed_in?' for whatever action you only want buyers to be able to do. You can also do more specific role-based authorizations as well - check out Devise' page
All in all, Tsiege's solution sounds pretty interesting. Let us know if you had any success with it!

Create new page in Rails to add roles to existing users

I want to create a new page in my rails app that you can access once you're logged in. All you would see is a dropdown with the existing users and a dropdown with the role you want to assign to that user with a submit button that would add the role to the user_role column for that user. Do I do this with a
rails g controller add_roles new create
or
rails g scaffold add_roles
How do I get it to submit the correct info to the user table?
From my understanding, a rails scaffold is a full set of controller, model, and migration. In your case, I don't think you want a add_roles_controller, and an add_roles model, you just want to update a column of your existing Users DB correct?
If so, ask yourself if you really need a controller to do this, this type of functionality can be done in an existing user_controller (or something of the like). If you are going the CRUD route, you can consider this an update upon a user.
You can make an active record call from any controller, lets say you're in a user_controller and you have a users model, you could do something like:
#users = Users.all
That would return an object of all the user's stored in the db from which can can loop through them, picking out each individuals role attribute.
If you need help on creating a form, you're going to need to elaborate, this will require changing your routes to respond to a POST to a certain controller action. That controller action can then take the parameters of the post, say a user's role, and update the Users database accordingly
if you haven't yet, check out the gem devise - it's a very easy way to login/logout and it includes some pretty awesome session management
Devise
And if you want more functionality, I'd look into rolify. I haven't used it but it seems like a great way to add roles to users. Rolify

What is the purpose of Rolify?

Hi I'm using rolify and have just realized that I'm not actually taking advantage of it's full potential.
At present I am doing things in my controller like re-routing users if current_user.has_role? :whatever_role, and allowing users if they have whatever other role...
Someone asked a question on stackoverflow about rolify and when I got to trying to answer it, I realized that I'm doing it wrong.
Now, here is where my confusion starts... Inside of ability.rb I have:
user ||= User.new # guest user (not logged in)
if user.has_role? :consumer
can :manage, Review
else
can :read, Review
end
Now let's say I add the consumer role to a user:
x=User.last
x.add_role :consumer
# => #<Role id: 10, name: "consumer", resource_id: nil, resource_type: nil, created_at: "2013-04-18 23:00:46", updated_at: "2013-04-18 23:00:46">
Right, so the role is created. I can check this by doing:
x.has_role? :consumer
=> true
Now I would expect this to give management ability for reviews...
x.has_role? :consumer, Review
=> true
but not for other models... here I try products
x.has_role? :consumer, Product
=> true
Further, when I look at "resource roles querying" and try to query the applied roles for reviews I find no applied roles:
Review.first.applied_roles
=> []
Can someone please explain rolify to me. Thanks
My answer, garnishing the question from this reddit post:
Authentication is establishing a User is who they claim to be.
Authorization is establishing that a User can perform a given action, be it reading or writing, after they've established their identity.
Roles are just common patterns of authorization across users: this User can be authorized as such, that User can be authorized like this instead.
The ingredient you're missing here is Permissions: a relationship between an established Role and some controller action.
Roles themselves make no promises about what action a User can perform. And remember--authorization is all about actions. Roles generalize what kind of User you're dealing with. They exist to keep you from having to query every User for a giant laundry list of Permissions. They declare: this User is a Role! Of course they have Permission to do that!
There are many types of Permission. You can store them in a database if you want your sufficiently authorized Users to be able to edit them, along with your Roles if those too ought to be configurable. Or, if your User's Roles are sufficiently static, you can manage Permissions in advance with Ruby code:
When I want to have configurable Roles and Permissions, i.e. for a client application you're handing off to someone at completion of contract, I implement a User :has_many Roles and a Role :has_many Permissions with my own custom models, and then add a before_filter :authorize hook into my ApplicationController, and write an authorize method on it that knows how to martial these expectations, or render a 403 page for those people who insist upon manually entering urls to things they hope expose actions to things they oughtn't have access to.
When I want to just have configurable Roles, I use Ryan Bates' CanCan gem.
When I want to have predetermined Roles and Permissions, I use Rolify in conjunction with Nathan Long's Authority, to get delightfully flexible Class-based Permissions via Authorizer classes.
Both Roles and Permissions can be either class-based or instance-based, depending on your use-case. You can, say, with the abilities of rolify you've just discovered, decide that Users may only act as a Role in certain, instance-based circumstances. Or, general Roles of User may only be able to execute an action given the object they are trying to action is of a certain type.
To explore the permutation of these, assuming a blog application, following the formula
a User who is a/an Role class/instance can action a/an/all/any/that (class/instance) Permission:
Role class and Permission class:
A User who is an Admin can delete any Post.
Role class and Permission instance:
A User who is an Admin can edit all Posts that they approved to be published
This would be easier if published posts had an approved_by field pointing to a User id. (Use a state machine gem for this sort of situation.
Role instance and Permission class:
A User who is an Author of a Post can comment on any Post
Note that this sort of situation is rare, which is why there are no gems I've mentioned above to handle this situation, except for perhaps the ability to manage predetermined circumstances like Rolify and Authority in conjunction; or, if you must pass this decision on to your client, your own custom solution.
Role instance and Permission instance:
A User who is an Author of a Post can edit that Post.
TL;DR:
Rolify is just for roles: grouping Users by Permission: access to a controller action. You have yet to decide how you are going to manage Permissions.
I hope this helps your understanding of Rolify's position in the grand scheme of authentication and authorization!

Resources