AdminUser and User, ActiveAdmin and Devise - ruby-on-rails

I need some help to implement my system requirements at this point, i'm a "newbie on Rails". I have the two gems (active_admin and devise) installed and the interaction after some modifications is not what i want.
I want to build the AdminUser authentication using email and password (the default ActiveAdmin behavior), and the system User is already being authenticated with a document_type and document_number and password. It means have the two entities separately on the system DB with different login logic.
The problem is that ActiveAdmin uses devise for the authentication and i having problems with the /admin/login page form, it's displaying the document_type and document fields that gets from the devise initial configuration file. I defined the document_type and the document as the keys of the User.
The workaround that i found to make the authentication was to delete the document and document_type conditions and use the email as the important value for the validation. Now my AdminUser model looks like this:
class AdminUser < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :login, :password, :password_confirmation, :remember_me, :document, :document_type
attr_accessor :document, :document_type
protected
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
puts "Conditions:" + conditions.to_s
document = conditions.delete(:document)
document_type = conditions.delete(:document_type)
where(conditions).where(["lower(email) = :value", { :value => document.strip.downcase }]).first
end
end
Sadly i have to say that this doesn't work for me. The authentication always fails, i tried a lot of variations without luck.
Researching i found the interesting idea to use the User model in both ways, but in this case they don't have common attributes and the roles are really different.
Anyone has implemented something like this? I hope yes.
Ideas are welcome.

Related

How To Recover a Password with Devise ( Ruby on Rails)

I'm trying to recover a user's password with devise, but it generates the following error
undefined method `reset_password_sent_at=' for #<User:0x007fb78cfafb68>
Can anyone help me with this, since I'm new to Ruby on Rails?
What is the best way to recover a password and email the user using Devise? Thank you very much...
I'm use devise (2.2.3)
User.rb
require 'digest/md5'
class User < ActiveRecord::Base
# Setup accessible (or protected) attributes for your model
belongs_to :shop
before_create :compute_email_md5
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable,
:recoverable,
:rememberable,
:trackable,
:validatable,
:token_authenticatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email,
:email_md5,
:password,
:password_confirmation,
:shop_id,
:role,
:terms,
:name,
:notify_on_order_received
validates :terms, :acceptance => true, :on => :create
end
THE SOLUTION IS
add reset_password_sent_at column to user table
As you've discovered, passord recovery requires that the model have a reset_password_sent_at column. Adding it via migration should solve this problem.
As for the reason this is happening, I'm guessing you added password recovery (the :recoverable module) after initially generating your Devise-enabled model (User). That's why Devise's generator didn't create that column for you.

Don't receive callback with devise_invitable

I'm using devise_invitable to allow users to invite each other. I want to set values for the user when the invite is created or when it's accepted. One approach is here
Using devise_invitable for adding Users to a Group in Ruby on Rails?
but this seems overkill. The callbacks look like a perfect solution, but they don't seem to fire during my Rspec tests.
Here is the user model:
class User < ActiveRecord::Base
belongs_to :company
rolify
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :invitable, :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :role_ids, :as => :admin
attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :company
validates :company, :presence => true
after_invitation_accepted :email_invited_by
before_invitation_accepted :email_invited_by
private
def email_invited_by
# This is NEVER executed during tests, even when an invite is successfully accepted
puts "Callback worked"
end
end
Any clues about where to look would be appreciated. I find the devise_invitable documentation a bit opaque.
Thanks!
For those still looking for an answer here is what worked for me.
The issue is not with validations since in devise_invitable there is a config to validate on invite and it defaults to false:
# Flag that force a record to be valid before being actually invited
# Default: false
# config.validate_on_invite = true
So my solution is to use the callback provided by devise_invitable:
after_invitation_accepted :create_profile
Do note that this needs to be below devise :invitable
devise_invitable callbacks will be fired if the user has been really invited (i.e. the object is persisted and there's an invitation token set) and the object (user's object) has no validation errors. That said, I see that you're validating presence of company without any conditions, which, I think, could be causing validation errors.
If that's the case, you can add a condition like this
validates :company, :presence => true, :if => Proc.new { self.invitation_token.nil? }
so it won't cause validation errors and fire the callbacks.

Rails : Adding an admin role using devise who can see all the users

I need to create an admin role using devise for my app. I've created basic authentication using devise . I have a devise user model in my app but now i need an admin who can show edit and destroy all the users. I tried following the tutorials but none of them helped.
I am using rails 3.0.10 and ruby 1.9.2-p290.
You just define role.rb first by creating migratioin
rails g model role name:string
then in role.rb
class Role
has_one:user
end
And in user model
class user
belongs_to :role
end
Insert two roles into DB
1.admin
2.user
Then check by this
if user.role.name == "admin"
# can do all your logic
else
your logic
end
Make sure insert role_id:integer into user model
Try it.......
I have similar requirement as yours and also don't want any user to be able to signup. All that will be taken care by Admin. Her what I've done.
I added another devise model called Admin
rails generate devise MODEL
Disable 'Registerable' for User model so that user cannot singup by themself
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :registerable, :timeoutable and :omniauthable
devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :first_name, :last_name, :role, :admin
# attr_accessible :title, :body
end
Enable CRUD for user by using sample from here: https://gist.github.com/1056194
Finally protect protect the users controller like so
users_controller.rb
# Add this
before_filter :authenticate_admin!
Hope this helps.

Devise - login from two model

I have two user models, first is from remote database as legacy and for internal company purposes. (Employee logins). Second is our project for public registration and sign in but I want one login form. I have searching long time, but some solutions are confusing for me.
First legacy looks like (only for reading and authentication):
class CrmUser < ActiveRecord::Base
require Rails.root.join('lib', 'devise', 'encryptors', 'sha1')
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable, :rememberable, and :omniauthable
establish_connection "crm_data"
set_table_name :users
devise :database_authenticatable, :encryptable, :authentication_keys => [:login]
alias_attribute :encrypted_password, :crypted_password
alias_attribute :password_salt, :salt
# Setup accessible (or protected) attributes for your model
attr_accessible :login, :password, :password_confirmation, :remember_me, :role_id, :first_name, :last_name
And second, for public and registration:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable, :rememberable, and :omniauthable
devise :database_authenticatable, :registerable, :authentication_keys => [:login]
alias_attribute :login, :email
# Setup accessible (or protected) attributes for your model
attr_accessible :login, :password, :password_confirmation, :remember_me, :role_id, :first_name, :last_name
Now I don't know how to do that User controller try to authentication from first model, and when user doesn't exists, go to second model and try it again.
Using:
Rails 3.1
Devise 1.4.3
EDIT:
In wiki of Devise is something about multiple model, but I'm little bit confused, there are not example more complex.
Thank you.
Regards, Rado
You should monkeypatch find_for_authentication method from devise/models/authenticatable.rb
module Devise
module Models
module Authenticatable
def find_for_authentication(conditions)
#put your authentication logic here
end
end
end
end
About authentication logic:
Using two models for authentication in your case it's realy bad idea. How do u want build relations with two users models? It's a lot of unnecessary code.
Correct way of resolving your problem is make some synchronization between yours tables.
Try to authenticate user with base User model.
If user credentials was wrong - try to authenticate him with CrmUser model.
If authentication with CrmUser was OK add him to users table if he doesn't exists there already.
Return User's model object.

How do I test my devise user model validations using RSpec?

I can find recommendations for testing devise user controllers and views in RSpec. I've also seen suggestions that the devise gem code is already tested so it's not useful to spend a lot of time reinventing the wheel.
However, my user model has other fields that I need validated when the user signs up. I'm using standard validates... statements in the user.rb model. For example:
validates_presence_of :nickname
I'm trying to use simple validation testing in my user_spec.rb, but when I try to create the user like this:
record = Factory.create(:user)
I get this error:
undefined method `encode!' for "Confirmation":String
The encode! method is not coming from my code, it must be one of the gems that devise is using, but I haven't been able to find it, yet.
I've tried creating the user using User.new and Factory Girl. I get the same error either way. This spec was passing until I did an update of all my gems. Unfortunately I didn't keep a note of everything that got updated at the time. I've tried rolling devise back to previous versions but still get the same error.
Rails 3, RSpec2
Thanks for any advice.
It seems to be fine, may be, my testing code helps you out:
user_spec.rb
require 'spec_helper'
describe User do
before :each do
#user = Factory.build(:user)
end
it "should not be valid without a first_name" do
#user.first_name = nil
#user.should_not be_valid
end
end
user.rb (Model)
class User < ActiveRecord::Base
validates_presence_of :first_name
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
devise :database_authenticatable, :registerable, :lockable,
:recoverable, :rememberable, :trackable
# Setup accessible (or protected) attributes for your model
attr_accessible :login, :first_name, :email, :password, :password_confirmation, :remember_me
attr_accessor :login
devise :database_authenticatable, :recoverable, :validatable
protected
def password_required?
!persisted? || password.present? || password_confirmation.present?
end
end

Resources