Rails 3 and Devise, Admin manages all about users - ruby-on-rails-3

I have a little app with Rails and Devise, and until now we were registering new users by Rails console. Now I have been asked to give a view for admin only, where they can signup, delete and view other Users.
My question is, which is the best way to go from here with Devise to accomplish this? I have checked similar questions here, on Devise wiki and other sites, and the conclusion I take from them is to have my own User controller.
What I need basically is a index view to list all users with a link on each one of them for editing and destroy and a new view for signup users. How much code from devise controllers I will new to override?
Also, my user model has the devise module: :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :timeoutable.
Thank you in advance.

From what it sounds like ... you just want have a client side for devise, (the user needs to register, login, etc. because they cant use the console). What I think your asking for, i think you should follow this tutorial to set up devise https://github.com/fortuity/rails3-subdomain-devise/wiki/Tutorial-%28Walkthrough%29 , (i followed this up to Set Up Subdomains, because that is what was important for me in my rails app). It should set up the functionality you are talking about. After you do this, if you find sign out throws an error, change
devise_for :users
in your routes, to
devise_for :users do
get "/users/sign_out" => "devise/sessions#destroy", :as => :destroy_user_session
end
If this wasn't what you were looking for, go into a little more detail

Related

Creating Users with admin AND registerable

I'm relatively new to ruby on rails, and so I am now very confused how to setup a user management system for admins.
Besides, users should be able to register themselfs (Devise Registerable).
I have a User controller, using devise_for :users and resources :users .
I can sign_up users, since I used the :registerable, flag in my Users model.
What I want to do now is to add the ability for admins to create users.
If I used the described system, I always get the message 'You are already signed in' when creating a new user through /users/new as admin. This is a message from devise.
So I followed the tutorial www.tonyamoyal.com/2010/07/28/rails-authentication-with-devise-and-cancan-customizing-devise-controllers/ to use cancan to restrict some actions and created a own devise registrations controller like described there.
My cancan ability model looks like this:
if user.has_role?(:admin)
#admin
can :manage, :all
elsif !(user.new_record?)
#logged in but no admin
...
else
# Guest
can :create, User
end
and my registrations controller like in the tutorial
class RegistrationsController < Devise::RegistrationsController
before_filter :check_permissions, :only => [:new, :create, :cancel]
skip_before_filter :require_no_authentication
def check_permissions
authorize! :create, resource
end
end
I also added the controller to the routes.rb
With this I can create new users with the admin, but if I want to sign_up as not logged in user ("#Guest") I get always the message cancan exception "Access denied". And if I call exception.subject in the CanCan exception handling it is empty.
Can it be, that 'resource' from my controller is not initialized? How can I get the expected behaviour?
Thanks a lot for your help ;-)
Mhm, I figured out, that resource seems to be a method of the devise-controller.
No idea, why it is not called, or is not returning an object
My solution was now (since I can only register users) to change
def check_permissions
authorize! :create, resource
end
to
def check_permissions
authorize! :create, User #could also be User.new
end
And with this it works. But I'm not sure, if it is the best solution ;-)

Multitenancy (acts_as_tenant) with Devise (users default scoped by subdomain) breaks sessions

Gems
ruby 1.9.3
rails 3.2.11
devise 2.2.3
acts_as_tenant 0.2.9
Code
All my models are scoped by a domain_id:
class User < ActiveRecord::Base
acts_as_tenant(:domain)
#...
end
Then, in my application_controller, I set the current tenant from the domain:
class ApplicationController < ActionController::Base
set_current_tenant_through_filter
before_filter :set_tenant
protect_from_forgery
#...
def set_tenant
#...
#domain = Domain.find_or_create_by_name(request.host)
set_current_tenant(#domain)
end
end
All works well for all models except for sessions: Everytime a page is loaded, it will log-out the first user who load a page with another tenant. By loading this page, it will log-out the first user who [... etc.]
Hypothesis: when Alice visits a domain, Rails loads current_tenant=alice_domain (ok). All works as expected, until Bob visits another domain, load current_tenant=bob_domain. When Alice refreshes her page, Rails still has current_tenant==bob_domain. Rails checks session: Alice does not exist with bob_domain scope, so Devise forces Alice logout. Then application_controller sets current_tenant=alice_domain... which logs-out Bob.
Dirty workaround: do not use acts_as_tenant in user model, scope users by domain myself in every controllers, then overwrite devise to scope login and registration by domain. And I'm unsure how to get Devise aware of current domain in sessions stuff. By the way, replacing acts_as_tenant by a manual default_scope in user falls in the same strange bugs. It seems very dirty to go this way.
I'm looking for a clean solution for days. I would be very grateful for any help.
Fixed, in application_controller, change
before_filter :set_tenant
to
prepend_before_filter :set_tenant
in order to default_scope everything, including User, before Devise checks the user's session.

Rails application design, user-dependent routing and content

I'm currently building a rails application that contains 3 user types. This is my first experience with web development, and I would like to avoid making crucial design errors that will cost me later on. Hopefully more experienced rails users and web developers will be able to guide me in the right direction.
I want to use Devise as my primary authentication system, and I am currently planning something like this in order to support 3 user-types within the Devise framework:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me
belongs_to :rolable, :polymorphic => true
end
For each of the three user-types:
# usertype1.rb
class UserType1 < ActiveRecord::Base
has_one :user, :as => :rolable
end
# usertype2.rb
class UserType2 < ActiveRecord::Base
has_one :user, :as => :rolable
end
Essentially, there is a polymorphic association between the user class and the several different user types. My hope is that this approach will allow me to eventually add different associative keywords within the user-type models (such as has-many) that will allow convenient querying of the database.
I'm also concerned about how to implement user-dependent routing. The idea is that each user-type will see a separate "hub" when they log-in, with different dashboards, different actions, etc. I was thinking that I would approach this by overriding the Devise SessionsController. Something like this:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
if user.type == 1
redirect_to hub_typeone
else if user.type == 2
redirect_to hub_typetwo
else
redirect_to hub_typethree
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: "Logged out!"
end
end
The idea is that upon successful authentication, the user is routed to a different page based on user type. I'm planning on using the devise current_user framework to then query the database to populate the hubs with the user-specific data.
Do you guys have any pointers for me? Do you see any huge flaws in my plans/reasoning/approach? Thanks in advance!
I get a feeling you are over-engineering this, and building something You Aren't Gonna Need It
It's best if you are clear about what the three different user types are. Most applications would require the following three user types:
Guest users, who aren't logged in, and can access some part of the application
Regular users
Admin users who administer the rights of regular users.
I am curious to know what other user types you would need if they are not in this list.
Devise wikipages has suggestions on how to create a guest user, and how to add an admin role. Probably best to start by implementing the functionality of the regular users of your application, and then use the above mentioned resources to add other user types.

Rails 3 Devise User table is missing authentication_token

My Rails 3 app is using Devise and I noticed that my users table was missing it's authentication_token column. Not sure how it's been authenticating users up until now, but in either case I'm looking to add the authentication_token column to repeat what was done in this tutorial: http://ariejan.net/2011/03/27/rails-3-devise-uploadify-no-flash-session-hacks. How do I go about adding this in?
Edit
I did notice that in my config/initializers/devise.rb I had this, which I take is an alternative to auth tokens?
# If true, uses the password salt as remember token. This should be turned
# to false if you are not using database authenticatable.
config.use_salt_as_remember_token = true
Edit 2
I also tried adding the following to my Users model but nothing changed.
devise :database_authenticatable
Here is my current user model:
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
Token authentication is only used for API style authentication where you receive a JSON response from another application. By default Devise uses email and password authentication, which is what the :database_authenticatable is configuring.
In order to set your app up this way you can follow either tutorial from the Devise Wiki. Either one of them will point you in the right direction.

Rails Devise Legacy Users from CakePHP

I recently got Devise working. New users sign in, sign up, logout etc etc just fine. Old users however have an issue. I have gotten it to a point where I get a 401 unauthorized, which seems to me that the hash is just incorrectly being created when signing in and of course not matching correctly.
My user model:
class User < ActiveRecord::Base
require "digest/sha1"
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :encryptable, :encryptor => :old_cakephp_auth
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
has_many :events
end
Cakephp uses sha1, but I don't know the specifics of how it does things. This obviously doesn't work, which is why I am here:
require "digest/sha1"
module Devise
module Encryptors
class OldCakephpAuth < Base
def self.digest(password, stretches, salt, pepper)
Digest::SHA1.hexdigest("#{salt}#{password}")
end
end
end
end
I got that from the how to add a custom encryptor example. They had this:
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
That didn't work either. Anyone have any ideas?
I saw a variation of this on the create your own custom encryptor wiki. I don't know how I didn't see it before. Perhaps someone updated it recently.
Place the following in your user model. It should overwrite valid password from devise:
def valid_password?(password)
return false if encrypted_password.blank?
Devise.secure_compare(Digest::SHA1.hexdigest(self.password_salt+password), self.encrypted_password)
end
You need to make sure to fill in the password salt you used in cake into all legacy user's rows. You also need to change password to encrypted password according to devise's instructions.
I feel like I may need to add a way encrypt from user model as well for new users. Or perhaps the custom encryptor I created handles that aspect.