Devise and a separate users table - ruby-on-rails

I'm working on a rails 3.2 app that authenticates using devise.
For a goal that is not related to the application (mostly statistics) I need to create a separate users table (let's call it alt_users) that only holds some fields of the users table (name, email, and some other fields) but no password digests and other sensitive infos. Also this records don't have to be modified if a user modifies his account or deletes it.
My idea is that when a user signs up, before devise makes his job some selected fields are inserted in the alt_users table.
What is the correct way to override devise behavior in order to make this happen?

What you can do is to override Devise's RegistrationsController in the following way:
In your routes.rb:
devise_for :users, :controllers => {:registrations => "registrations"}
Then create the file app/controllers/registrations_controller.rb :
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def create
# add your data to alt_users here
super
end
end
On a side note, if you can avoid overriding Devise's controller it would be best.
Try to think of other options like a before_create callback on the User model.

Related

Rails: invite to sign up as friend with devise gem

I'm using devise in my Rails App. I want user can give a link to their friends, and through the link, they can sign up and then become friends with their inviter.
Here is what I come up with.
First, I give every user a unique code, like dbgadf34t42a, and people could visit url like localhost/signup?invite_code=dbgadf34t42a. Then customize Devise's sign up controller, use this code to find the inviter and then create the friendship relationship.
Code would be something like
def create
#Create user account, and then create Friendship
invite_code = paramsp[:invite_code]
if user.save
inviter = User.find_by_invite_code(invite_code)
inviter.friendships.create(friend: user)
end
end
I'm wondering
If there is any better way of doing this, gems or codes.
I didn't find good resources on customize Devise's Signup Controller, can I extract the logic to another place, store the invite code, and then continue creating friendship model?
Perhaps something like:
def after_sign_up
if params[:invite_code]
redirect_to new_friendship_path
else
# default_behavior
end
end
If there is any better way of doing this, gems or codes.
You may use devise-inviteable gem. For friendship create you can customize this gem.
I didn't find good resources on customize Devise's Signup Controller, can I extract the logic to another place, store the invite code, and then continue creating friendship model?
To customise Devise Signup you need to inherit Devise::RegistrationsController
class RegistrationsController < Devise::RegistrationsController
def create
super
# Now write your customize code for friendship
end
end
And then tell devise to use that controller instead of the default with:
# app/config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}

Devise close registration but seed database with admin account

I'm looking to completely close off my registration system (temporarily) and only have 1 admin account that can be either raked into the database or seeded.
Is this possible with Devise at all? Or will a closed off registration also close off the seed/rake task with my admin user in it?
I currently have a user model with the typical devise setup, with an admin column that is a boolean - I'm currently setting that column in development by going into rails console and manually changing it.
Any help would be brilliant!
Thanks
There is a detailed step by step in the devise wiki; but basically you can either skip generating the registrations routes:
devise_for :users, :skip => :registrations
Which would make it a single user system by making it impossible to register.
This requires the first user to be created with either a seed file or through the console.
Or you could create your own controller to handle registrations which cuts off after the first user:
devise_for :users, :controllers => {:registrations => "registrations"}
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def create
if User.any?
redirect_to root_path, alert: 'Only one user allowed!' and return
end
super
end
end
Unless your seed / rake task is doing something really strange like automating a web browser then this will have no effect on your seed / rake task since they usually involve directly manipulating the DB through models and do not go though controllers at all:
# Example of seeding an admin user:
admin = User.create_with(surename: 'Doe', forename: 'John').find_or_create_by(email: 'admin#example.com')
admin.add_role(:admin)
You should be able to remove the devise routes for registration and still seed in the user. That user would then be able to login/logout, as long as you still have the devise routes for sessions.

How can I use devise with rails 4 to store data on a second model?

There are some similar questions but not clear answer.
I want to use devise I was able to add more fields and store them on the user table.
If I want to collect data during the signup process that belong to another table
is it possible to do it through devise controller or do I have to write my own one ?
You have to use your own. Override the registrations controller and add it to your routes to point your devise registration to your new registrations controller.
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
super
end
def create
# add custom create logic here
# Strip the fields out of the resource params and save them to
# another model then you can call super to have the method behave as it normal:
super
end
def update
super
end
end
Then add it to your routes
# app/config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
Depending on how you're structuring your form you might need to add the extra fields to the devise model (typically User) - you can use attr_accessor :field_name to do this if you must

Preventing user deletion in Ruby On Rails and Devise Application

I have a Rails 3.2.x application using Devise.
As per standard Devise feature, a user can delete his account (there is a button to click on the change passsword screen).
I want to prevent a user of deleting his account if he has made previous transactions in the system.
So I did the following in the user model
before_destroy do
# Only delete if no financial transactions exist
return false if Trxhistory.where(:user_id=>self.id).select(:id).count() != 0
end
It works, the user gets deleted if no transactions exist and the user does not get deleted if a transaction exists. BUT: in case the user is not deleted, the screen still shows the deletion success message rather than the error message.
To have such customization. I believe that you will have to overwrite the devise registrations controller.
The good news is that is not hard. all you have to do is generate a new controller on your app that will be the new registration controller for that user. for example.
bundle exec rails generate controller users/registrations
It will have to inherit from Devise:RegistrationsController
class Users::RegistrationsController < Devise::RegistrationsController
end
lastly you will have to reference this controller as the new registration controller at your routes.rb file just like the devise page says
devise_for :users, controllers: { registrations: "users/registrations"}
now you can implement your custom rule for that resource. i.e
class Users::RegistrationsController < Devise::RegistrationsController
def destroy
if resource.didsomething
redirect_to root_path, flash: { error: "You can't delete your account" }
else
super
end
end
end
the method above is overwriting the default destruction method of devise and calling the original one only if the condition is not met.

Devise/Rails - How to allow only admin to create account for others?

I am using devise as my authentication solution and now i am thinking about authorization. In my project I (the admin) is the only person authorized to create account for others.
I wonder if there is a way to do it without to much hack. In fact, Devise doesn't allow user to access to the signup page if he is already logged in.
Thanks for your advice on it!
Setting :skip => :registrations also kills the ability for a user to edit their user info. If that's not what you are after you can instead create a (minimal) custom registrations controller and only remove the new_user_registration_path while preserving the edit_user_registration_path.
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
# If you're not using CanCan, raise some other exception, or redirect as you please
raise CanCan::AccessDenied
end
end
# routes.rb
devise_for :users, :controllers => { :registrations => "registrations" }
Once you do this you also need to move the directory views/devise/registrations to just views/registrations.
You can try the rails_admin gem in conjunction with Devise to handle any admin-specific tasks. You'll need to add more code to set it up, but at least you avoid hacking around the solution in terms of changing your interactions with Devise.
It actually looks like in the later versions of Devise you can just remove the "registerable" declaration from your model and it will take care of this for you.

Resources