Design Question for multiple user models and cross creation of users

143 views
Skip to first unread message

Daniel

unread,
Jan 11, 2011, 4:46:52 AM1/11/11
to Devise
Hi,

I am writing a rails 3 app, which uses 2 different devise models.
Basically Customers and Employees. I want the employees to be able to
create accounts for customers. Based on a switch, a customer should
get a random password via e-mail or not. If not (aka the password is
empty) the customer should not be able to log into his account. I'm
not sure, what would be the best way to achieve that using devise.
What I tried is to not touch the generated devise methods, so the
customer can sign up on its own. Furthermore I created custom actions
for the form a employee should use to create a customer. But what
happens now is, that an employee can't create a customer unless he
supplies a passphrase, which should be, as I mentioned before
optional. Do I need to overwrite/extend the devise Controller actions
to achieve that or is there a built in way?

I tried to look through the existing discussions for a post related to
my problem. I didn't find anything, but if this kind of question has
already been answered, I'm sorry for asking again and it would be
nice, if you could point out the discussion for me.

Thanks,
Daniel

Andrés Mejía

unread,
Jan 11, 2011, 5:56:02 AM1/11/11
to plataforma...@googlegroups.com
So if understood correctly your question is: How to create a user without a password?", right?

I think this is hard to do in Devise, and I wouldn't suggest it anyway. What's wrong with setting up a random password in both cases?

Daniel

unread,
Jan 11, 2011, 6:06:53 AM1/11/11
to Devise
As I think about it, you're right. My problem boils down to the
question, how I can create a user without a password, who would be
deactivated by the definition of not having a password. Which leads me
to the question: Is it possible to disable a user account in a way
that the user is not able to log in? Because in this case i could
generate a random password, which won't get used anyway.

I thought about just using random paswords, too. I would use this
solution if there isn't a better one available, because, at least in
theory this creates a vulnerability if someone obtaines and cracks the
encryptes password, he could logon as this user and access all data
related to that user.

Andrés Mejía

unread,
Jan 11, 2011, 6:22:27 AM1/11/11
to plataforma...@googlegroups.com
A random 40 digit password takes at least a few million years to crack. It's probably the safest way to disable a user's account in a way that the user is not able to log in :)

John McGrath

unread,
Jan 11, 2011, 10:52:47 AM1/11/11
to plataforma...@googlegroups.com
I'm using the omniauthable module for facebook and twitter auth, which similarly requires creating an account where a password is unnecessary. Ask Andrés suggests I create a random password, by doing this in my User#find_for_twitter_oauth method:

User.create!( :email => data['email'], :etc => data['foo'], :password => :password => Devise.friendly_token[0,20])

Seems to do the trick.

Andrea Campi

unread,
Jan 12, 2011, 2:19:04 AM1/12/11
to plataforma...@googlegroups.com
Any time you want to override validation on your model, the simplest
solution is not to include :validatable in your Customer model, and
add your own validations instead.
You would copy most validations to be the same, but make you custom
ones conditional, like this:

with_options :if => Proc.new { |user| !Authorization.current_user ||

!Authorization.current_user.role_symbols.include?(:admin) } do |v|
v.validates_inclusion_of :accepted_tos, :in => [true, false]
v.validates_acceptance_of :accepted_tos, :accept => true
end


In this case however, since it's just the password, you only need to
override #password_required? in your model.
Devise has:

def password_required?
new_record? || !password.nil? || !password_confirmation.nil?
end

You just need to add your custom conditions and you're set. Something like:

class User
attr_accessor :password_required

def password_required?
if called_by_employee && unspecified_password
false
else
password_required?
end
end

def called_by_employee
current_employee # this will need tweaking based on how you do
authorization
end
end

This way, your controller only needs to pass :password_required from
your checkbox.

Hope this helps,
Andrea

Andrés Mejía

unread,
Jan 12, 2011, 3:55:20 AM1/12/11
to plataforma...@googlegroups.com
I still think it's simpler, cleaner and safer to just set a random password.

It's just one line of code.

Andrea Campi

unread,
Jan 12, 2011, 8:32:01 AM1/12/11
to plataforma...@googlegroups.com
2011/1/12 Andrés Mejía <and...@gmail.com>:

> I still think it's simpler, cleaner and safer to just set a random password.
>
> It's just one line of code.

Whatever floats your boat :)

But do note that "safer" depends on your context: whether your
application authorizes users for commenting on some blog or firing
nukes.
I can easily argue my solution is safer than using a random password,
since that has a small but non-zero likelihood of being cracked,
whereas a nil password is guaranteed to never allow login.
Also, a random password doesn't help you if, a year from now, you'll
need to find all users who don't have a real password.

But again, whatever works for you.

Andrea

Reply all
Reply to author
Forward
0 new messages