Administratively putting users into groups - ruby-on-rails

There are many users and one administrator. Users can create groups and send/receive requests to join those groups. That system works fine. I am now building separate "super groups" that the admin creates. These "super groups" don't rely on requests, they rely on appointment. The admin selects a user, selects a group, and adds the chosen user into the chosen group. How do I accomplish this?
How do I set it up so that the admin can simply pick a user(on their profile page), pick a group(preferably from a drop-down) and then make the association?
For example, as an admin, I would like to go to the user's profile page and on the profile page there is a drop-down(only admin-accessible) and add the user to the group of my choice. How would I accomplish this? Through a type of form? A boolean field? Could I just add an append method (<<) into my join model create action and have a select-tag for a group and then a create-submit button? I just need to be pointed in the general direction and I think that I can manage.
Of note: I am using a has_many :through association to capture the relationship. An admin has many "super groups" which are created/deleted fine. The "super group" has many members(users). I just need to know how to put users into a group administratively.

UPDATE - What is the best practice for adding a user to a has_many :through association via dropdown?
You are talking about wanting to add a user to a super group FROM the user's profile page. This means you want to pass a super_group_id to the Rails controller, find that super group, and then add the user to that group.
This is one option:
#user = User.find(params[:id]) # or user_id, depending on the controller
#super_group = SuperGroup.find(params[:super_group_id])
#super_group.users << #user
Original Answer:
How are you currently creating and deleting the Super Groups? I assume you have a SuperGroupsController. One way to accomplish this is to have a sub-controller SuperGroups::UsersController with your same RESTful actions (create, update, etc). Those restful actions handle the assigning/removing of the users to groups. This allows you to separate the checking that you need to do to make sure only an admin is taking these actions.
class SuperGroups::UsersController < ApplicationController
before_action :verify_admin # create this method to do the checking
def create
# create a user super group association here
end
def delete
# remove a user from the super group here
end
end
This is apparently a best practice according to DHH. I first used this method after reading this article and I've found this pattern very clean and useful.

Related

How do associations affect the way we create objects in the controller?

I understand that associations are important because this gives us a way of linking two objects together so they have a 'relation' and we can query through both of them. For example,
A landing page belongs to a blog user & a blog user can have many landing pages
We obviously go into the models and apply the correct methods 'has_many' and 'belongs_to'. We also create a migration and add the foreign key to the 'belongs_to' model. This being the 'landing page'.
My problem:
When creating a landing page, it is possible to choose a blog user. This obviously passes the blog user ID into the params. I want to save this ID into the foreign key field in the landing page model.
Is this possible without doing:
def create
#landing_page = #blog_user.landing_pages.build(landing_pages_params)
end
Why do you have to go through a blog user? Another example:
def new
#landing_page = #blog_user.landing_pages.new
end
What is the purpose of doing it this way? Surely passing the ID into the field is enough without going through the blog_user?
Sure, you could do something like
#landing_page = LandingPages.new(blog_user_id: X)
Obviously, you need to know the ID of the BlogUser record. You'll then be able to access the newly associated BlogUser as you'd expect
#landing_page.blog_user #=> BlogUser(id: X)

ActiveAdmin - Allow non-logged-in users to view but not edit resources

I have a Rails app that I'm using to display database records. Until I have the time/knowledge/resources to create a home-brewed interface for viewing the database records (with pagination and advanced search/sort functionality), I've opted to settle for ActiveAdmin to handle these tasks for me.
The database needs to be publicly viewable, and I really don't want to force casual users to create user accounts, so the obvious choice seems to be to disable authentication altogether. However, I only want for admin users (i.e.; me - not unregistered users) to be able to edit the database records, preferably through the ActiveAdmin interface.
Is there an easy way to accomplish this (disable create/edit/delete for unregistered users but allow them for admins)?
ActiveAdmin lets you customise its permissions by providing a custom AuthorizationAdapter. This has an authorized? method that determines whether a user can perform an action. Here's an AuthorizationAdapter should allow logged-in admins to do anything, but others can only read data:
class AdminOnlyEditAdapter < ActiveAdmin::AuthorizationAdapter
def authorized?(action, subject = nil)
:read == action || (user && user.admin?)
end
end
Then configure ActiveAdmin to use your new class in config/initializers/active_admin.rb:
config.authorization_adapter = "AdminOnlyEditAdapter"

Ruby on Rails / MVC - Splitting Views for different user levels

I have a Rails application which handles hotel room reservations. I would like an admin to see all reservations and specific users to only see their reservations. Is the 'proper' way of doing this:
Create a new action for each user in the reservation controller
OR
Put an if statement in the index action, deciding whether to return all reservations or only those for a user id sent by parameter
I have it set up and working the second way but I'm not sure this is the correct way of doing things.
I would do this by having a single view, which is populated by the appropriate collection of reservations. For an admin this would be all reservations, but for a regular user the collection would only contain their bookings.
This then requires a single if statement in the controller to ascertain the appropriate reservations:
if user.is_admin?
#reservations = Reservation.all
else
#reservations = user.reservations
end
The above code assumes that you've setup an appropriate relationship between a user and their reservations, but you get the idea.

Rails + Devise: How to restrict a user from editing records that do not belong to him

I'm using Rails, Devise and Mongoid.
A user can only have one project (has_one :profile) but all users (and non authenticated users) can see a list of projects (I have this working). When a user is logged in they see "edit and delete" buttons next to the projects (via wrapping those buttons in <% if user_signed_in? %>). However, a signed in user sees these buttons next to all project and can edit or delete them all.
How do I restrict a logged on user to only be able to edit only his project?
As a bonus, is it possible to show specific content or html around the project that belongs to the signed in user (such as text that says "this is your project" or an additional class around the project's html)?
CanCan is great when you have multiple users being able to modify the same resource, and you need to keep track of who has which permissions. But if it's strictly the case that only the user who owns the project can modify it, CanCan is probably overkill.
Hide the links in the view as suggested by iouri, and then in your controller do something like:
def edit
if current_user != #project.user
# Redirect them to an error page
else
# Render the view
end
end
Better yet, create a method like:
def user_owns_project?
#project.user == current_user
end
Then set up a before filter for edit, update and destroy to redirect to the error page if the user doesn't own the project.
EDIT: Your before filter will also ned to find the project and set #project. CanCan takes care of this for you too with load_and_authorize_resource, but I'd still avoid using it unless you need, or expect to need, fine-grained permissions control.
Devise is to control "authentication", this should not to be your responsibility.
You want to control "authorizations", for that CanCan is better.

Dynamic roles and permissions system in Rails app

I need to create roles based permissions systems in my Rails app. I would be totally happy with CanCan, but the main problem - it has to be dynamic, so that Admin has to be able to assign permissions and to create new roles. The permissions can be simple controller/action restrictions, and can be data related, for example some users can edit only their own profiles, and some of them can edit the profiles of all the users in the particular group. And it would be really nice to allow Admin to create new permissions.
What I'm thinking about is to store in db a controller/action, and some data related restrictions (I'm really confused here about the way to define them). So could you please give me some advice, what would be the best way to organize permissions?
Any thoughts are much appreciated
If you like CanCan, then I think is best to use it. Here is a short tutorial about storing abilities in database so non-programmers can update them:
https://github.com/ryanb/cancan/wiki/Abilities-in-Database
If you really, really want to implement such system yourself. Depending on your needs, I will suggest for you to implement it as simple as possible.
In the case you need only users to have access to modules(certain controllers). You can do:
Store all users permissions in just like serialized fields -> http://apidock.com/rails/ActiveRecord/Base/serialize/class
class User
serialize :permissions, Array
def access_to?(module)
permissions.include? module.to_s
end
end
some check when setting this field would be nice.
Just make a check on top of every controller if the current user have access to this controller(section)
class ApplicationController
private
def self.require_access_to(module)
before_filter do |c|
unless c.send(:current_user).try :access_to?(module)
c.send :render_no_presmissions_page
end
end
end
end
class AdminNewsController
require_access_to :news
end
Of course this is just a start position, from where you can easily evolve.
[EDIT The link given by #RadoslavStankov is a better answer than this.]
You can do it with CanCan easily. Just make a model for permissions (which has_and_belongs_to_many :users), and in your Ability#initialize load the permissions appropriate to the user from the model and say that the user can do them. Then make appropriate user interface for administrating that model.
Something like this:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
user.permissions.each do |permission|
can permission.symbol, permission.scope
end
user.prohibitions.each do |permission|
cannot permission.symbol, permission.scope
end
end
end
where scope returned something like :all for nil scope, or Object.const_get(#scope_name) otherwise... Play with it. Anyway, it's doable.
More complex CanCan things are likely to be more complex (duh) - for example conditional permissions - but that would be a bitch to administer as well, so I think this should be enough for most applications.

Resources