Mass assignment and roles in Rails - ruby-on-rails

I have Users, Roles, and Network models in Rails 3. Users and Networks have a HMT relationship through Roles. If a User has an Role type of 'admin' with a specific Network, he/she can change the Role of other Users.
It seems like the Role type should not be available via mass-assignment. So how does a Network admin change the position type of other Users? I actually think this is a really basic question, but I just can't find the answer.
I am using CanCan and have a current_user method. Does that simply mean the controller would have a simple if/then check to see if the user has the appropriate role in a network?
Does mass assignment only apply to pages that have no authentication?

So a couple things
You'll presumably display a role select box on the users/1/edit page if the user is an admin
On the update action on the controller, you'll have some kind of authorization to make sure the user is an admin
When the time comes to make the update
:
class myModel < ActiveRecord::Base
attr_accessible :some_attr, :other_attr
attr_accessible :some_attr, :other_attr, :role_id, :as => :admin
end
class myController < ApplicationController
#admin check before doing the following
if #user.update_attributes(params[:user], :as => :admin)
redirect_to root_path
end
end

Related

how to authenticate user and admin with the same login form in rails

I have created a user authentication using devise in rails app .Now i have to create a new model for Admin.i can do that by either creating a new admin model(devise) or write roles in user model like
example
class User < ActiveRecord::Base
enum :roles[:admin,:superadmin]
end
but how should I login as admin when without creating another SIGNUP OR LOGIN form.or if i create a diffrent regestration and login for admin how can I hide that from users.Inshort i need to create a admin panel and dashbord for admin and need some authorizations.iam new to rails plz help.also you can suggest me another approch for doing it (i dont want selec box or checkbox in my login for roles because anyone can become admin then)
EDIT:
I want to know about the authentication for admin and user ,authorization is the next part .if i create a diffrent admin registration form any user can come and become admin.what will be the other approch?.
Basically you can make additional model Role which will be [admin, superadmin, user] and will be related to User.
let's say user can have only one role (has_one) so when user is created you should assign a particular role to him. This way you can simply use:
current_user.role.name #=> "admin"
Good practice is to implement methods in User class:
def admin?
role.name == "admin"
end
def user?
role.name == "user"
end
So you can simply call: current_user.admin?.
I suggest you to use some authorization library, for restricting/allowing access to diff parts on your application.
There is a plenty of them, like Pundit, CanCan etc ...
Hope this will help you to start, then you will see how many options you have ;)
Update:
You're assigning role to user during registration process, or via admin panel later.
About register form, you will have RegistrationController which is overridden from Devise so you can simply put user.role = Role.find_by_name("user") before creating user.
This is default role for all users who are registered via register form. But, you will have some admin dashboard where you can change role for users and assign to them maybe to be moderator, admin, superadmin etc..
About login form, there is no need to assign role but just to get current_user and to get his role.
Let's say you have 2 different navigations for user & admin. When user is successfully logged in, in you application.html.erb layout you can do simply check :
<% if current_user.admin? %>
<%= render "navigation/admin_navigation" %>
<% elsif current_user.user? %>
<%= render "navigation/user_navigation" %>
<% end %>
This way you will show appropriate navigation, so this is authorization on view level.
You can also have authorization logic on controller level, for certain actions:
class PostsController < ApplicationController
before_action :authorize_admin, only: [:index]
private
def authorize_admin
redirect_to root_path, alert: "Permissions denied" unless
current_user.admin?
end
end
This way you're allowing ONLY admin to access to Posts#index.
Hope it's more clear now :)
Cheers
Very simple would be to create column for example "admin" type boolean in user model and based on that make permissions to administration.
You can create permisson check in application_controller.rb like this
def check_admin
unless current_user.admin
redirect_to '/', :alert => "Don't have permission!"
end
end
And use it in controller for actions only admin can make like this:
before_action :check_admin, only: [:edit, :create]
For more scurity use separate models for User and Admin with separate routes and view for Public and Admin users.
It is not direct answer to your question, but read some info on STI - single table inheritance.
And wherever you need special behavior for the admin you can just check if user type is admin
The simplest thing I can think of is to add a role column on the users table and check the value, for example:
class User < ActiveRecord::Base
def role
super.try(:inquiry)
end
end
user.role.admin?
It depends on your needs, do you really need a Role model or a separate User and Admin model. Do you need to know any more than is this user an admin, if not, this is an easy and simple solution.

Devise: Allow only admin to create users

I have a Rails 4 app. It is working with devise 3.2.3. devise is properly integrated. At this point, users can register with email and password, sign in and perform CRUD operations.
Now here is what I would like to do: Instead of having any user to sign up by themselves, I want to create an admin. The admin would retain the responsibility of creating users. I don't want users to sign up by themselves. Basically the admin will create the user, issue them their log-in credentials, and email it to them.
I read this post and similar ones in SO and in devise wikis to no avail.
I have added a boolean field to users table to identify admin users.
class AddAdminToUser < ActiveRecord::Migration
def change
add_column :users, :admin, :boolean, :default => false
end
end
I have read about managing users using cancan but I don't know how to use it to achieve my objective
The solution i'm looking for would probably require a combination of devise and cancan.
I would appreciate any guidance on this matter.
Make sure that the boolean :admin is not in your params.permit() area for strong parameters.
Use the pundit gem, it is maintained and pretty much plain old ruby objects.
Then in your UserPolicy you would do something like this
class UserPolicy < ApplicationPolicy
def create?
user.admin?
end
end
And your model would look something like this
class User < ActiveRecord::Base
def admin?
admin
end
end
Last in your controller you make sure that the user is authorized to do the action
class UserController < ApplicationController
def create
#user = User.new(user_params)
authorize #user
end
end
You would probably also want to restrict the buttons that are shown that would give access to the admin user creation section. Those can be done with pundit as well.

Rails: Using CanCan to assign multiple roles to Users for each organization they belong to?

A User can belong to many Organizations. I would like User to be able to be assigned different roles/authorizations for each of the organization it belongs to.
For example, user "kevin" may belong to organization "stackoverflow" and "facebook." kevin should be able to be an admin for stackoverflow, and a regular member(read+write) for facebook.
However, the CanCan gem only seems to address user roles for a single organization. I'm still a beginner, but from what I can gather, the CanCan gem assumes user roles are tied only to the main app.
How would I be able to assign separate roles for different organizations, preferably using the CanCan gem?
You're thinking that you have to save roles as a string field in the User model. You don't have to, at all:
class User
has_many :roles
end
class Role
belongs_to :user
belongs_to :organization
attr_accessible :level
end
class Ability
def initialize(user)
can :read, Organization
can :manage, Organization do |organization|
user.roles.where(organization_id:organization.id,level:'admin').length > 0
end
can :write, Organization do |organization|
user.roles.where(organization_id:organization.id,level:'member').length > 0
end
end
end
we have something like this. the solution is to override the current_ability method. in your case, you probably have a join table for users and organization. let's call that user_organizations. In this join table, you probably also store the user's role for a particular organization, right? So let's use that table to define the current ability. In your application controller
def current_ability
# assuming you have a current_user and current_organization method
Ability.new UserOrganization.where(user_id: current_user.id, organization_id: current_organization.id).first
end
# ability.rb
class Ability
include CanCan::Ability
def initialize(user_organization)
user_organization ||= UserOrganization.new
case user_organization.role
when 'admin'
when '...'
when nil
# for users not a member of the organization
end
end
end
hope this gives you some idea

Rails polymorphic user model with Devise

So I know this question has been ask a ton of times but my question goes a little bit further.
When modeling my application I have two types of users that have a polymorphic association to the user model. Such as:
class User < ActiveRecord::Base
belongs_to :profileable, :polymorphic => true
end
class User_Type_1 < ActiveRecord::Base
has_one :user, :as => :profileable
end
class User_Type_2 < ActiveRecord::Base
has_one :user, :as => :profileable
end
The reason I did this, instead of an STI, is because User_Type_1 has something like 4 fields and User_Type_2 has something like 20 fields and I didn't want the user table to have so many fields (yes 24-ish fields is not a lot but I'd rather not have ~20 fields empty most of the time)
I understand how this works, my question is I want the sign up form to only be used to sign up users of type User_Type_1 but the sign in form to be used to both. (I will have an admin side of the application which will create users of User_Type_2)
I know I can use the after_sign_in_path_for(resource) override in AppicationController somehow to redirect to the right part of the site on sign in. Something like:
def after_sign_in_path_for(resource)
case current_user.profileable_type
when "user_type_1"
return user_type_1_index_path
when "user_type_2"
return user_type_1_index_path
end
end
So I guess my questions are how would I make the form to work with Devise and only allow signups of type User_Type_1 and then sign them in after sign_up?
Also, if I am going about this the wrong way, what is the right way?
I was able to answer my own question and am putting it here so that maybe it can help someone else with the same problem.
The login problem was easy, just use the default devise login and the after_sign_in_path_for in ApplicationController as described above
I realized the answer to the form question as typing it out here:
I just created a normal form for the User_Type_1 with nested attributes for User
and had it post to the UserType1Controller
Then saved both objects and called the sign_in_and_redirect helper from Devise
class UserType1Controller < ApplicationController
...
def create
#user = User.new(params[:user])
#user_type_1 = UserType1.new(params[:patron])
#user.profileable = #user_type_1
#user_type_1.save
#user.save
sign_in_and_redirect #user
end
...
end
Then the after_sign_in_path_for method from above sent it to the right place and it was all good.

Creating an organization in the user model, UNLESS current_user is signed in..?

How can I make it so that an organization is only created if the user is NOT signed in?
That's a little vague, so let me make that a little clearer. I have two tables; one organization table, and another user table. Organizations has many users, and users belong to an organization.
# models/organizations.rb
class Organization < ActiveRecord::Base
has_many :users
I made it so that when a user signs up, an organization is created along with his account.
# models/user.rb
class User < ActiveRecord::Base
belongs_to :organization
before_create :create_organization
private
def create_organization
self.organization = Organization.create :name => self.name
end
Cool, that works.
But users should also be able to sign other people up for an account, and that new user's organization_id should be the same as current_user.organization_id
*# controllers/users_controller.rb*
def create
#user = User.new(params[:user])
if current_user
#user.organization_id = current_user.organization_id
end
end
This solution is limiting me, because the model is creating an organization even if the user is already signed in. They work independently (if I take out either the before_filter in the model or the if current_user in the controller), but not together.
I'm having a difficult time making them work together because you can't access current_user in the user model.
I'd put the organization_id as a paramater in the sign up link, but that's not very secure as that means any user could simply change the organization_id in the URL and automatically get an account to another organization that doesn't belong to them.
If it matters, I'm using Authlogic as my authentication solution.
Is there anything I can do in the user model or the user controller to accomplish this?
Just check if organization is present in the before_filter:
def create_organization
self.organization = Organization.create(:name => self.name) unless self.organization.present?
end
If a user is signed in, the new user will be associated with an organization already and the before_filter will not create a new one.

Resources