I have a registration form, and after registration I want browser to remember user's (still unconfirmed) email. How could I do that? I assume I can do this somehow with build_resource of RegistrationsController.
Assuming you want to remember the last registered/un-confirmed user you could do this:
Create new folder under app/controllers called my_devise
Create a file called registrations_controller.rb in app/controllser/my_devise:
class MyDevise::RegistrationsController < Devise::RegistrationsController
# POST /resource
def create
build_resource
if resource.save
# here we save the registering user in a session variable
session[:registered_as] = resource
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_up(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
respond_with resource
end
end
end
Update the config/routes.rb file to tell Devise to use our new controller:
devise_for :users,
:controllers => {
:registrations => 'my_devise/registrations'
}
After registration, the session variable :registered_as will now hold the last user that registered and could be referenced in any controller or view:
some_view.html.rb:
<p>Registered as:
<%= session[:registered_as].inspect %>
</p>
See also: Override devise registrations controller
Related
By default with devise. After a user registers it automatically signs them in after sign up. Is there anyway to register a user and not auto sign them in and redirect to the login page?
You need to override Devise::RegistrationsController#create. You can see how registration works here
First, create a custom controller subclass of Devise::RegistrationsController
class RegistrationController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
resource.save
yield resource if block_given?
if resource.persisted?
if resource.active_for_authentication?
set_flash_message! :notice, :signed_up
respond_with resource, location: root_path # Change this to whatever route your want
else
set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
set_minimum_password_length
respond_with resource
end
end
end
Then tell devise to use custom controller:
devise_for :users, :controllers => {:registrations => "registrations"}
Assuming User is the model of course.
I am trying to change slightly the behaviour of one devise controller method. Here it says I can do that running rails generate devise:controller users.
However doing that just generated commented code with a bunch of super calls. If I don't know what the super methods do, how am I supposed to edit the lines of code I want to change?
The modification I want to do is simple: if there is no admin user yet (none with role=admin was found), then the user's role will be set to admin, else, it will be a normal user. So I thought in this case an after_filter would be the solution, so I did this:
class UserController < Devise::RegistrationsController
after_filter :set_role, only: [:create]
protected
def set_role
admin_user = User.find_by_role(User::admin_role)
if admin_user.nil?
#user.role = User::admin_role
else
#user.role = User::default_role
end
#user.save
end
end
My routes:
devise_for :users, controllers: { users: "users" }
However, the method is not even being executed. Why? What can I do?
I think you need to be overriding the registrations controller:
devise_for :users, :controllers => {:registrations => "registrations"}
Then the controller:
controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
admin_user = User.find_by_role(User::admin_role)
if admin_user.nil?
resource.role = User::admin_role
else
resource.role = User::default_role
end
if resource.save
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_up(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
respond_with resource
end
end
end
I have a Rails application that uses Devise for user authentication. If a user registers using the registration form, but he happens to use an existing valid username/password, instead of giving an error, I want to just log in the user. But I can't figure out how to do that.
Any suggestions?
You will need to override the devise RegistrationsController create action. After the regular registration code, you will need to add your code to check if a user already exists and sign in if the email/pass combination match. Something like this (based on the devise version you are using - this is based on the source of 2.2.4)
class RegistrationsController < Devise::RegistrationsController
def create
build_resource
if resource.save
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_up(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
# Add code to check if user exists and sign in
# I am just pasting in the sign_in code here and you will need to customize it as per your needs
# You can directly use params and User model, or try an keep your code generic
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_in_path_for(resource)
end
end
end
And add the controller to your routes as well:
devise_for :users, :controllers => { :registrations => "registrations"}
User model has one user_profile.
I just installed devise and its working fine.
I made registrations_controller.rb and it has 'create', 'after_update_path_for(resource)
', and 'edit' actions.
If I want to make it input '45' to nested column of user_profile as default value, how can I code in registration controller???
Should I make another action called 'save/or new?' , and write this?
#user.user_profile.language_id = '45'
I was making some tests, and I suggest you to use callbacks, but you can also override the actions of the RegistrationsController of Devise. I followed this thread: Override devise registrations controller and the code of the controller https://github.com/plataformatec/devise/blob/master/app/controllers/devise/registrations_controller.rb (see that I use sign_in instead of sign_up - I'm working with Rails 3.2.8)
And this is the code with the edits for the case:
class RegistrationsController < Devise::RegistrationsController
def new
super
end
def create
build_resource
resource.build_user_profile
resource.user_profile.language_id = 45
if resource.save
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
respond_with resource
end
end
def update
super
end
end
And as the answer of the post said, I leave the routes as follows:
devise_for :users, :controllers => {:registrations => "registrations"}
I used a has_one relationship.
I'm trying to redirect users that have failed the sign up form (e.g. they entered a username that is already taken, they left a field blank, etc...)
I have custom failure set up for users that fail the sign in form, code below:
class CustomFailure < Devise::FailureApp
def redirect_url
root_path
end
def respond
if http_auth?
http_auth
else
redirect
end
end
However, I've been stuck on how to set this up for sign up failure. Ideally I would just like to redirect them back/to root_path, any ideas? Thank you!
You will probably need to subclass Devise::RegistrationsController and override the create action. Just copy over the create method from here and modify the redirect on failure to save.
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def create
# modify logic to redirect to root url
end
end
Change your routes to tell Devise to use your controller:
# config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
It's a bit tedious to modify certain parts of devise to suit your needs and I suspect it's because the gem does a good job to cover most common cases. However, edge-cases for use of devise are a lot and your question points to one of them. I had to do something similar, that is, make sure devise redirects to a specific page when a user does one of the following:
submits form on an empty form
submits an already existing email.
Below is how I handled it.
First, create a controller called RegistrationsController that inherits from Devise::RegistrationsController like so:
class RegistrationsController < Devise::RegistrationsController
end
Inside this controller you will have override the create method in devise. Go to the devise github page here, https://github.com/plataformatec/devise/blob/master/app/controllers/devise/registrations_controller.rb to view the create method and copy the code in that method. Then create a private method to override the returning statment of the last block of the if statement. Your controller should look like so,
class RegistrationsController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
resource.save
yield resource if block_given?
if resource.persisted?
if resource.active_for_authentication?
set_flash_message! :notice, :signed_up
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
set_minimum_password_length
response_to_sign_up_failure resource
end
end
private
def response_to_sign_up_failure(resource)
if resource.email == "" && resource.password == nil
redirect_to root_path, alert: "Please fill in the form"
elsif User.pluck(:email).include? resource.email
redirect_to root_path, alert: "email already exists"
end
end
end
It should work.
Tip:
To keep flash error messages add this line before the redirect_to in your override
resource.errors.full_messages.each {|x| flash[x] = x}
So in your registrations_controller.rb :
def create
build_resource(sign_up_params)
if resource.save
yield resource if block_given?
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_flashing_format?
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
resource.errors.full_messages.each {|x| flash[x] = x} # Rails 4 simple way
redirect_to root_path
end
end
In config/routes.rb:
devise_scope :user do
get '/users', to: 'devise/registrations#new'
end