I am using devise invitable in my app: a user fills a form with email, that creates a user in my database and sends an invitation to the email address. The other person can then confirm its account by setting up his password.
Everything works fine until the invited user tries to log in by setting up his password. When he submits the form, I get this error:
undefined local variable or method `this' for #
here's my invitation controller:
class Users::InvitationsController < Devise::InvitationsController
def new
#user = User.new
end
def create
#user = User.new
#user.save
end
def update
if this
redirect_to root_path
else
super
end
end
private
# this is called when creating invitation
# should return an instance of resource class
def invite_resource
## skip sending emails on invite
resource_class.invite!(invite_params, current_inviter) do |u|
u.skip_invitation = true
end
end
# this is called when accepting invitation
# should return an instance of resource class
def accept_resource
resource = resource_class.accept_invitation!(update_resource_params)
## Report accepting invitation to analytics
Analytics.report('invite.accept', resource.id)
resource
end
end
What is this "this" thing ?
Related
I am adding Devise to an existing application. The authentication file is inside lib/omniauth/strategies/standard.rb. There is also multiple lib/omniauth/strategies/clientname_saml.rb files for the app (one per Apartment tenant). Due to the current sprint, I'd like to add Devise gradually and thus keep the current user.authenticate method. We're using a number of gems which automatically recognize the #current_user which Devise sets.
I've tried adding sign_in(:user, user) in the callback_phase below, but I get the error: NoMethodError (undefined method `sign_in' for #<OmniAuth::Strategies::Standard>)
module OmniAuth
module Strategies
class Standard
include OmniAuth::Strategy
include Rails.application.routes.url_helpers
def request_phase
if strategy_supported?
redirect(new_session_path(request.params))
else
fail!('strategy_unsupported')
end
end
def callback_phase
# binding.pry
if strategy_supported?
email = standard_params[:email] || ''
user = User.find_by(email: email.downcase)
if user && !user.locked? && user.authenticate(standard_params[:password])
sign_in(:user, user)
super
else
redirect(sessions_failure_path(safe_params))
end
else
fail!('strategy_unsupported')
end
end
private
def standard_params
request.params.symbolize_keys.slice(:email, :password)
end
def safe_params
request.params.symbolize_keys.slice(:email, :code, :target)
end
def strategy_supported?
Preference.get(:login_strategy) == 'standard'
end
end
end
end
I was able to solve it by using include Devise::Controllers::Helpers.
I am trying to send an welcome email in a rails application after a user signs up. Currently I have a redirection that will take them to a specific page. I have a mailer method that I want to send but it doesn't work. Is there another way to do this?
def after_sign_up_path_for(resource)
if current_user
ModelMailer.new_user_notification(#user).deliver
'/dashboard'
end
end
You could send the email in the user model, with a simple after_create:
class User << ActiveRecord::Base
# ...
after_create: send_welcome_email
def send_welcome_email
ModelMailer.new_user_notification(self).deliver
end
end
Just set up my first mailer on Rails 4. I have a welcome email sent to new users as soon as they sign up (create) for a new account using devise.
I also have devise set up so that if a current_user is not found, a guest user will be created. Unfortunately, this is interfering with the mailer. Every time a guest account is created, the mailer will send an email to a non-existing email.
I am having trouble figuring out how to exclude the guests from the mailer.
user.rb:
after_create :send_welcome_mail
def send_welcome_mail
UserMailer.welcome_email(self).deliver
end
mailers/user_mailer.rb:
class UserMailer < ActionMailer::Base
default from: "example#gmail.com"
def welcome_email(user)
#user = user
mail(:to => user.email, :subject => "Welcome!")
end
end
application_controller.rb (guest creation):
def current_or_guest_user
if current_user
if session[:guest_user_id] && session[:guest_user_id] != current_user.id
logging_in
guest_user(with_retry = false).try(:destroy)
session[:guest_user_id] = nil
end
current_user
else
guest_user
end
end
# find guest_user object associated with the current session,
# creating one as needed
def guest_user(with_retry = true)
# Cache the value the first time it's gotten.
#cached_guest_user ||= User.find(session[:guest_user_id] ||= create_guest_user.id)
rescue ActiveRecord::RecordNotFound # if session[:guest_user_id] invalid
session[:guest_user_id] = nil
guest_user if with_retry
end
private
# called (once) when the user logs in, insert any code your application needs
# to hand off from guest_user to current_user.
def logging_in
# For example:
# guest_comments = guest_user.comments.all
# guest_comments.each do |comment|
# comment.user_id = current_user.id
# comment.save!
# end
end
def create_guest_user
u = User.create(:name => "guest", :email => "guest_#{Time.now.to_i}#{rand(100)}#example.com")
u.save!(:validate => false)
session[:guest_user_id] = u.id
u
end
I'm sure this is easy, but I am still new to rails and am a bit confused on the best way to go about this. Let me know if you need any other code.
def welcome_email(user)
# The following line is unnecessary. Normally, you do
# something like this when you want to make a variable
# available to a view
##user = user
# You can make the if more explicit by writing
# if user.id == nil, but if will return false in
# Ruby if a value doesn't exist (i.e. is nil)
if user.id
mail(:to => user.email, :subject => "Welcome!")
end
end
So I have an app in which the users login with their cell phone numbers and get notifications via text/sms. It's a mobile app. I send texts via the applicationmailer by sending emails to "33333333#vtext.com" etc.
However, I have hit a wall with how to override the password reset instructions. I want the message to be sent via text (i don't have their email address), but how do I override devise to do this? I can have the user enter in their number and then do a lookup (i store the contact path as a field in the user, I generate the string in the backend, they don't have to do it).
Ideas?
thanks a bunch!
You can do this by changing your
passwords_controller:
def create
assign_resource
if #resource
#resource.send_reset_password_instructions_email_sms
errors = #resource.errors
errors.empty? ? head(:no_content) : render_create_error(errors)
else
head(:not_found)
end
end
private
def assign_resource
#email = resource_params[:email]
phone_number = resource_params[:phone_number]
if #email
#resource = find_resource(:email, #email)
elsif phone_number
#resource = find_resource(:phone_number, phone_number)
end
end
def find_resource(field, value)
# overrides devise. To allow reset with other fields
resource_class.where(field => value).first
end
def resource_params
params.permit(:email, :phone_number)
end
and then including this new concern in the users model
module Concerns
module RecoverableCustomized
extend ActiveSupport::Concern
def send_reset_password_instructions_email_sms
raw_token = set_reset_password_token
send_reset_password_instructions_by_email(raw_token) if email
send_reset_password_instructions_by_sms(raw_token) if phone_number
end
private
def send_reset_password_instructions_by_email(raw_token)
send_reset_password_instructions_notification(raw_token)
end
def send_reset_password_instructions_by_sms(raw_token)
TexterResetPasswordJob.perform_later(id, raw_token)
end
end
end
which basically uses the private methods that the devise method sent_reset_password_instructions uses adding your own texting logic.
I'm trying to set up gradual engagement in my utility app which people can use without registering e.g. notepad.cc and jsfiddle.net and I plan to create a guest user (with Devise) for the user when he 'writes' to the app.
I found this guide on the Devise wiki https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user which shows how to create a guest user for the duration of the browser session. What I want is for the user to continue using the same guest account in subsequent visits, until he signs up, maybe when I introduce subscription plans for more features.
How can I modify what's in the guide to make this possible?
Code in the guide linked above:
# file: app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
# if user is logged in, return current_user, else return guest_user
def current_or_guest_user
if current_user
if session[:guest_user_id]
logging_in
guest_user.destroy
session[:guest_user_id] = nil
end
current_user
else
guest_user
end
end
# find guest_user object associated with the current session,
# creating one as needed
def guest_user
User.find(session[:guest_user_id].nil? ? session[:guest_user_id] = create_guest_user.id : session[:guest_user_id])
end
# called (once) when the user logs in, insert any code your application needs
# to hand off from guest_user to current_user.
def logging_in
end
private
def create_guest_user
u = User.create(:name => "guest", :email => "guest_#{Time.now.to_i}#{rand(99)}#email_address.com")
u.save(false)
u
end
end
And using it in the controller:
#thing.user = current_or_guest_user
#thing.save
After some yak-shaving I've managed to get it to work. Here's the working code:
class ApplicationController < ActionController::Base
protect_from_forgery
# if user is logged in, return current_user, else return guest_user
def current_or_guest_user
if current_user
if cookies[:uuid]
logging_in # Look at this method to see how handing over works
guest_user.destroy # Stuff have been handed over. Guest isn't needed anymore.
cookies.delete :uuid # The cookie is also irrelevant now
end
current_user
else
guest_user
end
end
# find guest_user object associated with the current session,
# creating one as needed
def guest_user
User.find_by_lazy_id(cookies[:uuid].nil? ? create_guest_user.lazy_id : cookies[:uuid])
end
# called (once) when the user logs in, insert any code your application needs
# to hand off from guest_user to current_user.
def logging_in
# What should be done here is take all that belongs to user with lazy_id matching current_user's uuid cookie... then associate them with current_user
end
private
def create_guest_user
uuid = rand(36**64).to_s(36)
temp_email = "guest_#{uuid}#email_address.com"
u = User.create(:email => temp_email, :lazy_id => uuid)
u.save(:validate => false)
cookies[:uuid] = { :value => uuid, :path => '/', :expires => 5.years.from_now }
u
end
end
I will accept another answer if you can show me a better way to do this.
The above solution works great.
Don't forget to setuphelper_method :current_or_guest_user to make the method accessible in views. Took me some time to figure out.