Rails CanCan questions with has_many :through model case - ruby-on-rails

In my rails application, my Users have many Projects through Participants.
Currently I am using CanCan for authorizations. I have done some research and can't quite figure out how to do the following.
In my ability.rb file I want to provide :manage abilities to to Users on Projects. Currently that looks like:
can :manage, Project if user.has_role? :silver
My Participants table has user_id and project_id. How do I only give those manage capabilities to users that are associated with a project via the participants table?

I am currently using the following as a solution. I would prefer using a solution native to devise or cancan.
In the model.
def is_participant?(participant)
self.participants.exists?(:project_id => participant)
end
And in my view.
<% if current_user.is_participant?(#project.id) %>

Related

Set Up Admin Users to Edit Users, Articles, Collaborators

I am trying to solve an issue I'm having with setting up admin on my site. Here is a simple version of my routes.
resources :users
resources :articles
resources :collaborators
end
resources :admin
Admin users are very similar to Collaborators, because they can edit and create Articles, but Admin has the ability to also c.r.u.d. Users, Collaborators, and Articles for every User. Collaborators can only c.r.u.d. Articles that are associated with the User they have been assigned to.
The part where this gets a little bit confusing is how to set up the controller and views that Admin uses for CRUD operations. As of now the way I am trying to implement it is to create separate CRUD views within admin/. The problem with this is that the functionality is so simimlar to a collaborator, I feel like it could be DRYer somehow.
Anybody know the most basic way to implement something like this? Thanks!
Update: I'd like to update this to say that it's super easy to google admin tools for rails. I'm more wondering how to implement this without an admin tool, or if that sounds like a bad idea, why?
The answer I came up with is to create Collaborators with an admin field true / false. I also set up CanCan and it's working pretty nicely.
Here is my CanCan ability.rb
def initialize(user)
if user.admin?
can :manage, :all
else
can :manage, Article, :id => user.article_id
cannot :index, Article
end
end
I just used "user" because it's more readable and shorter than collaborator and basically a user...
Try ActiveAdmin (http://activeadmin.info/). I think it is the most simplest way to build administrator backend for your application.

Authorization gem for a multi-tenancy application?

Are there are any authorization gems/examples for multi-tenancy applications?
I looked at CanCan and CanTango, but I wasn't able to find what I am looking for.
My app has Account, User, Relationship model. The relationship model has a relationship_type column which determines authorization level. Its value can be owner, moderator, editor, perhaps more in the future. Users can own/moderate many accounts, and an account can have many owners/moderators.
All the examples I found describe a single tenant application, whereas my app's authorization has to be scoped through the current account being viewed. A user can be a guest on one account and an owner of another, for example.
I'm starting to think my Relationship model is bad design and might have drawbacks, but I'm not sure what is a better alternative.
CanCan can indeed handle this because it lets you define arbitrary ruls. Your ability file might look like this:
def initialize(user)
can :read, BlogPost do |blog_post|
blog_post.account == user.account and user.relationship.in?([:owner, :moderator])
end
end
Try declarative_authorization, the authorization rules are defined in a single Ruby file using a DSL and you can define advanced rules based on objects' attributes and on the user role of course.
For example you can say something like this
role :moderator
has_permission_on :accounts do
to :manage
if_attribute :moderators contains {user}
end
end
declarative_authorization offer several methods you can use in models/controllers/views, for example in the account view you can use something like:
<% permitted_to? :update, #account do %>
<%= link_to 'Edit account', edit_account_path(#account) %>
<% end %>
You can have a look at the documentation and at the RailsCasts episode.

Whats the best approach for using sorcery(auth) with multiple user classes?

I`m looking to create two models: trainer & client.
When signing up those two types of models share the basic auth info, such as email & password.
Thus I would like to use Sorcery to do the authentication for me, the gem creates a User model by default.
Searching through StackOverflow I understand I could use Single Table Inheritance, which most people find problematic.
Is there a better/simpler solution for those two types of users to share the basic auth info but be separate models which would contain their role specific data?
I`m sorry if I mixed things up.
What kind of "role specific data" do your two users have?
I was in a very similar situation as you are in an app that I'm still developing. I chose to use a role based approach using CanCan.
class User < ActiveRecord::Base
has_one :client_profile # or whatever a client has here
has_one :trainer_profile # or whatever a trainer has here
end
Then, you would define your abilities
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # anonymous user
if user.is? :trainer
can :create, TrainerProfile
# some other trainer specific roles here, like editing his/her profile
elseif user.is? :client
can :create, ClientProfile
# some other client specific roles here, like editing his/her profile
end
end
end
Of course, the above code assumes an is? method on the User class to check the user role.
More info on CanCan can be found on the CanCan wiki, and also the Railscast on CanCan.

Design Question for ActiveAdmin

I'm a newbie to the ROR world and I'm trying to use ActiveAdmin to design the Admin Panel for an Artists Portfolio Website.
The idea is that each artist has a login/password and can manage assets.
The models are set with has_many in the AdminUser table, and belongs_to in the linked models.
For example, an AdminUser has_many Videos.
There are many linked assets.
What would be the best approach so that:
The currently logged in AdminUser only has access to his own assets?
The currently logged in AdminUser is set as the admin_user_id field
for each newluyy created asset?
Thank you very much for your help!
I am not sure if this answer is in time.
Q1. The currently logged in AdminUser only has access to his own assets.
A1. use cancan for your authorization framework. By default ActiveAdmin doesn't provide the authorization ability for you. so , the key code may looks like:
# in your app/models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
can :read, Asset, :admin_user_id => user.id
end
end
for more detailed steps of using Cancan (very easy, you can deal with it in 15 minutes ), please refer to : https://github.com/ryanb/cancan
Q2. The currently logged in AdminUser is set as the admin_user_id field for each newluyy created asset.
A2: AdminUser is just a "User" model. so, you can call it "current_user" in your view and controller as the regular Devise's way. e.g.
#in your controller
def create_xx
# save the admin_user_id to the newly created asset.
Asset.create(:admin_user_id => current_user.id)
end
for more details of Devise, see its official website: https://github.com/plataformatec/devise

multiple roles in rails

I want to design a role based system like Basecamp. A user can be editor of a brand and also he can be a worker in another brand. I'm using devise + cancan. How can i design a database for this situation? Thanks.
I would recommend a role model. In this scenario a user would have_and_belong_to_many :roles while a role would have_and_belong_to_many :users. This creates a many to many relationship between roles and users. See this RailsGuide for more info on associations.
In your CanCan ability.rb file you can do something like this (I am just guessing at your setup):
can :manage, Brand do |brand|
user.has_role?("brand_manager") && user.brands.include?(brand)
end
In your user.rb file it's helpful to write something like this:
def has_role?(name)
role = Role.find_by_name(name)
(self.roles.include?(role)) ? (return true) : (return false)
end
Hope this helps.
acl_system2. Its an old plugin, but checkout its readme file to see if it serves the purpose.

Resources