How to edit create registrations_controller action using devise? - ruby-on-rails

I'm making a simple app that has the traditional User model, but also a Patients model. I want a user to automatically become a patient on sign up.
I've managed to follow instructions here, and can see the file users/registations_controller.rb, but I'm not sure what to add to it.
I have pasted the existing devise create code from here
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
respond_with resource
end
end
and I want to add functionality to do this too:
# #user = User.new(user_params)
#patient = #user.build_patient
#patient.save
But I don't know how to do that? (do I just add the code and replace 'user' with 'resource'?)

You can do it by adding block code like this instead of copy the Devise code
class YourController < Devise::RegistrationsController
def create
super do |user|
#patient = user.build_patient
#patient.save
end
end
end

Related

on sign up if email already exist then render user on specific page where i can display some message

i just want to send confirmation instructions to user again if email already exist.
Thats what i've implemented, it just let user to sign Up if email is unique. if email already exist it just don't do anything.
class RegistrationsController < Devise::RegistrationsController
layout 'pages'
def new
build_resource
yield resource if block_given?
respond_with resource
end
def create
build_resource(sign_up_params)
admin = User.create(first_name: "")
resource.authenticatable = admin
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: accounts_get_started_path(resource)
end
else
byebug
clean_up_passwords resource
set_minimum_password_length
respond_with resource
end
end
def edit
super
end
def update
super
end
def destroy
super
end
end
If the email already exists you should resend devise confirmation mail by doing this:
Devise::Mailer.confirmation_instructions(resource).deliver
You can use valid? runs all the validations within the specified context. Returns true if no errors are found, otherwise it returns false. (Refer to this link for more info.)
NOTE: Here I am assuming you have uniqueness validation on email field. (Refer this link for more info)
If you have validation, then your code looks like
def create
build_resource(sign_up_params)
.
.
if resource.valid?
# your code for saving details
else
# Your code to redirct to different page
redirect_to where_you_want
end
end

change registrationcontroller create action failure redirect path

I'm trying to implement a signup form on the homepage of my app. The successful flow (registering) works perfectly. The problem lies in when a validation fails, namely triggering a rerender of the devise registration :new action. I would like this rerender to happen on the homepage instead of devises own view.
I've tried to rewrite the devise controller by adding the root_path location to the "respond_with location" as seen below, however for some reason this continues to trigger a render of the devise views.
# POST /resource
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
respond_with resource, location: root_path # HERE!!!
end
end
I'm wondering what a clean way would be to fix this problem
EDIT
It just struck me that I could render the home layout with the preferred template, however this feels a bit improper.
# POST /resource
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
render layout: 'frontend/home', template: 'frontend/home/index'
end
end
I eventually went with the approach as appended with the edit above:
render layout: 'frontend/home', template: 'frontend/home/index'

Rails double render error despite using if then statement

I frequently use both render and redirect_to but combining in an if...then statement so that the action by default only has 1. Not sure why this is not working in this case with Devise.
What I need to do is whether a user is confirmed or not, immediately after s/he signs up successfully I need to POST to another controller to create some other things, which is why the redirect_to is the same. But I'm getting the DoubleRender error
Thanks!
For your reference, this is the Devise code:
# POST /resource
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 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
set_minimum_password_length
respond_with resource
end
end
Then my code:
def after_sign_up_path_for(resource)
redirect_to "/plan_date_create"
end
def after_inactive_sign_up_path_for(resource)
redirect_to "/plan_date_create"
end
The respond_withs do a render and then after_sign_up_path_for and after_inactive_sign_up_path_for do redirects, and you're calling both respond_with and one or the other of those methods on the same line of code.

What does the devise default create action look like?

So, I'd like to add this bit of code to the devise registrations controller.
When I'm calling #user.save. just before that, I need to call, #user.uid = SecureRandom.hex(whatever-value).
However, I don't want to change the way the create action currently functions. I'd just like to add the #user.id = SecureRandom.hex line.
So, how does the original devise create action look?
https://github.com/plataformatec/devise/blob/master/app/controllers/devise/registrations_controller.rb
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_with resource
end
end
even more docs:
https://github.com/plataformatec/devise/wiki

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