Adding to Devise's Registrations Controller - ruby-on-rails

So I have a user model via devise and a collective model. I'm trying to create an invite system such that a user can invite a person to the website via email. When this person joins the website, a user is created and this new user will automatically be added to a collective using a token (the collective they are added to is chosen by the inviting user). I have the invite system working up to the point that a non-user receives an email with a sign up link (with a token in the url) and gets to the sign up page. I cannot however manage to get this person added to a collective once they submit the registration form.
I am currently getting the error Validation failed: Owner can't be blank due to the line resource.collectives.push(org)in the create action. Help would be much appreciated!
My Custom Registrations Controller (I copied & slightly modified the Devise Registration Controller code)
class RegistrationsController < Devise::RegistrationsController
def new
#token = params[:invite_token]
build_resource({})
#validatable = devise_mapping.validatable?
if #validatable
#minimum_password_length = resource_class.password_length.min
end
yield resource if block_given?
respond_with self.resource
end
def create
build_resource(sign_up_params)
#added #token
#token = params[:invite_token]
resource_saved = resource.save
#added if #token logic
if #token != nil
org = Invite.find_by_token(#token).collective
resource.collectives.push(org)
end
yield resource if block_given?
if resource_saved
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
#validatable = devise_mapping.validatable?
if #validatable
#minimum_password_length = resource_class.password_length.min
end
respond_with resource
end
end

Related

How to edit create registrations_controller action using devise?

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

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

Rails 4 + Devise: Send welcome email with password reset instructions

I have my registrations set up such that I create the account for a user with a predetermined password, then I would like to send them a welcome email, with a link to the Devise edit_user_password_url.
My method fails because when the User follows the link, they see the following: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
How can I make my welcome email include the proper link for password reset?
# RegistrationsController
def create
if params[:user] && !params[:user][:password]
params[:user][:password] = "testpassword" #obviously not real
build_resource(sign_up_params)
puts 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?
NewUserMailer.new_user_email(resource).deliver_now
redirect_to users_path
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
render :new, :address => params[:address]
end
else
super
end
end
#email
Welcome, follow this link to update your password <%= link_to "My account", edit_user_password_url %></p>

How to Track Devise User Registration as Conversion in Google Analytics

I'm using Devise with my Rails 3.2 app and I want to be able to add track new registrations as conversions in Google Analytics. I'd like to have the new users directed to the same page that they are being redirected to now, if possible (i.e. may be a pass thru view that redirects to the current page users are redirected to after create).
Can someone please help me figure out the best way to do this with Devise?
# users/registrations_controller.rb
# POST /resource
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
clean_up_passwords resource
respond_with resource
end
end
def after_sign_up_path_for(resource)
after_sign_in_path_for(resource)
end
From the top of my head, I'd use flash.
The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed to the very next action and then cleared out.
On the registrations_controller.rb:
if resource.active_for_authentication?
flash[:user_signup] = true # or something that you find more appropriate
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
Then, on the view that you redirect to after a signup, I'd render the necessary code to trigger a Google Analytics event based on the presence of flash[:user_signup].
You can do it from your controller:
Step 1: in order to keep it organised, you can create a file app/controllers/concerns/trackable.rb with the following content:
module Trackable
extend ActiveSupport::Concern
def track_event(category, action)
push_to_google_analytics('event', ec: category, ea: action)
end
def track_page_view
path = Rack::Utils.escape("/#{controller_path}/#{action_name}")
push_to_google_analytics('pageview', dp: path)
end
private
def push_to_google_analytics(event_type, options)
Net::HTTP.get_response URI 'http://www.google-analytics.com/collect?' + {
v: 1, # Google Analytics Version
tid: AppSettings.google_analytics.tracking_id,
cid: '555', # Client ID (555 = Anonymous)
t: event_type
}.merge(options).to_query if Rails.env.production?
end
end
Step 2: Replace your tracking ID.
Step 3: Finally, track your conversions in your controller:
# app/controllers/confirmations_controller.rb
class ConfirmationsController < Devise::ConfirmationsController
include Trackable
after_action :track_conversion, only: :show
private
def track_conversion
track_event('Conversions', 'from_landing_page')
# or # track_event('Conversions', user.email)
end
end
Extra: you can also use the track_page_view method to track specific actions that don't have views (like API requests).
More info here: https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide.

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