Customizing devise controller - ruby-on-rails

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

Related

Devise register and login rails

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.

Devise sign up AJAX not working

I am trying to setup a registration form using devise and AJAX.
On a newly generated app it works perfectly but when I try and add it to a project, I do not have success
registration controller
https://gist.github.com/mosinski/8568126
my partial form:
https://gist.github.com/mosinski/8577429
my application.js:
https://gist.github.com/mosinski/8577480
my inicializer:
https://gist.github.com/mosinski/8577533
my application helper:
https://gist.github.com/mosinski/8577564
my form is partial in bootstrap modal.
The whole problem is that it not sending as js but as text/html why ?! ;]
1. Routes
Have you declared the custom controllers in your routes.rb file?
#config/routes.rb
devise_for :users, controllers: { sessions: "sessions", registrations: "registrations" }
2. Forms
Are you sure you're sending the request from your partial form?
Devise generates its own views (which you can typically find at /views/devise). If you're using the standard Devise forms, you'll be sending standard HTML mime-types, and so you'll have to ensure you're using your partial
That's all I can glean from your code currently! Of course we can discuss any fixes in the comments
Update
Here's our working registrations controller:
class RegistrationsController < DeviseController
prepend_before_filter :require_no_authentication, :only => [ :new, :create, :cancel ]
prepend_before_filter :authenticate_scope!, :only => [:edit, :update, :destroy]
before_filter :configure_permitted_parameters
prepend_view_path 'app/views/devise'
# GET /resource/sign_up
def new
build_resource({})
respond_with self.resource
end
# POST /resource
def create
build_resource(sign_up_params)
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_to do |format|
format.json { render :json => resource.errors, :status => :unprocessable_entity }
format.html { respond_with resource }
end
end
end
# GET /resource/edit
def edit
render :edit
end
# PUT /resource
# We need to use a copy of the resource because we don't want to change
# the current user in place.
def update
self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
prev_unconfirmed_email = resource.unconfirmed_email if resource.respond_to?(:unconfirmed_email)
if update_resource(resource, account_update_params)
if is_navigational_format?
flash_key = update_needs_confirmation?(resource, prev_unconfirmed_email) ?
:update_needs_confirmation : :updated
set_flash_message :notice, flash_key
end
sign_in resource_name, resource, :bypass => true
respond_with resource, :location => after_update_path_for(resource)
else
clean_up_passwords resource
respond_with resource
end
end
# DELETE /resource
def destroy
resource.destroy
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
set_flash_message :notice, :destroyed if is_navigational_format?
respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
end
# GET /resource/cancel
# Forces the session data which is usually expired after sign
# in to be expired now. This is useful if the user wants to
# cancel oauth signing in/up in the middle of the process,
# removing all OAuth session data.
def cancel
expire_session_data_after_sign_in!
redirect_to new_registration_path(resource_name)
end
protected
# Custom Fields
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:first_name, :last_name,
:email, :password, :password_confirmation)
end
end
def update_needs_confirmation?(resource, previous)
resource.respond_to?(:pending_reconfirmation?) &&
resource.pending_reconfirmation? &&
previous != resource.unconfirmed_email
end
# By default we want to require a password checks on update.
# You can overwrite this method in your own RegistrationsController.
def update_resource(resource, params)
resource.update_with_password(params)
end
# Build a devise resource passing in the session. Useful to move
# temporary session data to the newly created user.
def build_resource(hash=nil)
self.resource = resource_class.new_with_session(hash || {}, session)
end
# Signs in a user on sign up. You can overwrite this method in your own
# RegistrationsController.
def sign_up(resource_name, resource)
sign_in(resource_name, resource)
end
# The path used after sign up. You need to overwrite this method
# in your own RegistrationsController.
def after_sign_up_path_for(resource)
after_sign_in_path_for(resource)
end
# The path used after sign up for inactive accounts. You need to overwrite
# this method in your own RegistrationsController.
def after_inactive_sign_up_path_for(resource)
respond_to?(:root_path) ? root_path : "/"
end
# The default url to be used after updating a resource. You need to overwrite
# this method in your own RegistrationsController.
def after_update_path_for(resource)
signed_in_root_path(resource)
end
# Authenticates the current scope and gets the current resource from the session.
def authenticate_scope!
send(:"authenticate_#{resource_name}!", :force => true)
self.resource = send(:"current_#{resource_name}")
end
def sign_up_params
devise_parameter_sanitizer.sanitize(:sign_up)
end
def account_update_params
devise_parameter_sanitizer.sanitize(:account_update)
end
end

How can I pass email of unconfirmed user to the session (Devise)?

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

How can I set the value to the nested column when signing up with Devise?

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.

Devise: redirect on sign up failure?

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

Resources