I am using Apartment and Devise gem for Muti-tenancy and authentication.
I have a sign_up page in root domain URL(example.com) where I get the subdomain details from user.
I need to sign_in the user after successfully saving the record and redirect to the new subdomain(sub.example.com).
Apartment Schemas:
Account => Common for all schemas(Public)
User => Created seperately for each schemas(Private)
RegistrationController:
class Users::RegistrationsController < Devise::RegistrationsController
...
...
def create
ActiveRecord::Base.transaction do
#account = Account.new(account_params)
if #account.valid?
# Create & switch to the new tenant
Apartment::Tenant.create(#account.subdomain)
Apartment::Tenant.switch!(#account.subdomain)
#account.save
sign_in(:user, #account.user)
redirect_to root_url(subdomain: "#{Apartment::Tenant.current}")
else
render :action => 'new'
end
end
end
...
...
protected
def account_params
params.require(:account).permit(:name, :subdomain, user_attributes: [:first_name, :last_name, :email, :password, :password_confirmation])
end
end
The above code successfully redirects to the new subdomain but, It is not signing_in the user although I am signing_in the user before redirect.
Anyone please help me to redirect the user as signed_in to the new subdomain.
Thank you..
Finally, solved this issue by adding :domain => :all or the rootdomain :domain => 'example.com' option in session_store which I found in this answer.
config/initializers/session_store.rb
config.session_store :cookie_store, :key => '_domain_session', :domain => :all
(or)
config.session_store :cookie_store, :key => '_domain_session', :domain => 'example.com'
Related
I'm trying to take a user-inputted email address, store it in the DB, and then send a welcome email to that address. If this is successful, the user should be redirected back to root. Locally this is happening correctly, but on my Heroku production server, the address is getting saved in the DB, but the user is then redirected back to subscribers. This is the API call for saving a subscriber, but it doesn't have a corresponding view.
The email is also not being sent, although that may be a separate issue. If it matters, I'm trying to use MailGun to send the email.
I'm not sure which of these files are necessary, but...
routes.rb:
Rails.application.routes.draw do
root to: 'pages#home'
resources :subscribers, only: :create
end
/controllers/subscribers_controller.rb:
class SubscribersController < ApplicationController
def new
#subscriber = Subscriber.new
end
def create
#subscriber = Subscriber.new(subscriber_params)
if #subscriber.save
SubscribeMailer.subscribe_email(#subscriber).deliver
flash[:success] = "Success! Check your email."
redirect_to root_path
else
flash[:danger] = "Oops! That's not a valid email."
redirect_to root_path
end
end
private
def subscriber_params
params.require(:subscriber).permit(:email)
end
end
/models/subscriber.rb:
class Subscriber < ActiveRecord::Base
validates_email_format_of :email, uniqueness: true
end
/mailers/subscriber_mailer.rb:
class SubscribeMailer < ActionMailer::Base
default from: "email#gmail.com"
def subscribe_email(subscriber)
mail(to: subscriber.email, subject: 'Subject')
end
end
/config/environment.rb:
# Load the Rails application.
require File.expand_path('../application', __FILE__)
# Initialize the Rails application.
Rails.application.initialize!
ActionMailer::Base.smtp_settings = {
:port => ENV['MAILGUN_SMTP_PORT'],
:address => ENV['MAILGUN_SMTP_SERVER'],
:user_name => ENV['MAILGUN_SMTP_LOGIN'],
:password => ENV['MAILGUN_SMTP_PASSWORD'],
:domain => 'subdomain.herokuapp.com',
:authentication => :plain,
}
ActionMailer::Base.delivery_method = :smtp
In looking at some other StackOverflow threads, OPs were asked for prod logs. I ran heroku logs, but didn't see anything that sticks out.
I finally figured it out. I was using a sandbox domain for Mailgun, and the email I was testing with wasn't the same one I authorized for use through Mailgun.
Devise throws:
"NoMethodError (undefined method `login' for #<ActionDispatch::Request:0x00000004e42d80>):
"
every time I try to log in.
In this application "login" field is used as authentication key:
/config/initializers/devise.rb:
config.authentication_keys = [ :login ]
In session_controller.rb I used before_filter:
def configure_permitted_parameters
devise_parameter_sanitizer.for(:user) { |u| u.permit(:login, :password) }
end
And my routes.rb:
devise_for :users, :controllers => { :sessions => 'sessions', :registrations => 'registrations', :invitations => 'users/invitations'}
This problem appeared after upgrade from Rails 3 to Rails 4.
Can someone explain to me, what I'm doing wrong?
UPDATE
My bad. Found wrong parameter in devise initializer, set by my co-worker.
Anyway i have error message:
NameError (undefined local variable or method `invitation_token' for #<User:0x0000000286c750>):
app/controllers/sessions_controller.rb:6:in `create'
sessions#create:
def create
self.resource = warden.authenticate!(auth_options)
sign_in(resource_name, resource)
render :json => { :user_id => resource.id }, :status => :created
end
UPDATE
Crap. My co-worker also changed database.yml to another DB. So this DB was not migrated to last state =. After rake db:migrate all works fine. Thanks to all.
The underlying issue here is generally that devise's invitable code is generated by an second step in your devise work flow, a generator that makes a second migration:
$ rails g devise_invitable:install
$ rails g devise_invitable User (where User is my Model)
$ rake db:migrate
What you need to check for is if both migrations are in sync (in my case I reran the user migration but NOT the invitable migration and thus my user table was incorrect).
According to this link, you should create a login virtual attribute in the User model.
#Virtual attribute for authenticating by either username or email
#This is in addition to a real persisted field like 'username'
attr_accessor :login
Also add login to attr_accessible for rails 3
attr_accessible :login
You may also need to overwrite Devise's find_for_database_authentication method in User model
(assuming it is activerecord)
# app/models/user.rb
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
else
where(conditions).first
end
end
You may need to modify config/initializers/devise.rb to have
config.reset_password_keys = [ :login ]
config.confirmation_keys = [ :login ]
I have a custom mailer (UserMailer.rb) and a few methods to override the default Devise methods for the welcome email and forgot password emails. The mailer uses a custom template to style the emails--and it works great.
In config/initializers, I have a file with
module Devise::Models::Confirmable
# Override Devise's own method. This one is called only on user creation, not on subsequent address modifications.
def send_on_create_confirmation_instructions
UserMailer.welcome_email(self).deliver
end
...
end
(Again, UserMailer is setup and works great for the welcome email and reset password email.)
But what's not working is the option to "Resend confirmation instructions." It sends with the default Devise styling and I want it to use the styling of my mailer layout. I know I can manually add the layout to the default Devise layout, but I'd like to keep DRY in effect and not have to do that.
I've tried overriding the send_confirmation_instructions method found here, but I'm getting a wrong number of arguments (1 for 0) error in create(gem) devise-2.2.3/app/controllers/devise/confirmations_controller.rb at
7 # POST /resource/confirmation
8 def create
9 self.resource = resource_class.send_confirmation_instructions(resource_params)
In my initializer file, I'm able to get to this error by adding a new override for Devise, but I'm probably not doing this correctly:
module Devise::Models::Confirmable::ClassMethods
def send_confirmation_instructions
UserMailer.send_confirmation_instructions(self).deliver
end
end
Any ideas?
You don't have to go through that initializer to do that. I've done this by overriding the confirmations controller. My routes for devise look like:
devise_for :user, :path => '', :path_names => { :sign_in => 'login', :sign_out => 'logout', :sign_up => 'signup'},
:controllers => {
:sessions => "sessions",
:registrations => "registrations",
:confirmations => "confirmations"
}
Then, create the confirmations_controller and extend the Devise::ConfirmationsController to override:
class ConfirmationsController < Devise::ConfirmationsController
In that controller, I have a create method to override the default:
def create
#user = User.where(:email => params[:user][:email]).first
if #user && #user.confirmed_at.nil?
UserMailer.confirmation_instructions(#user).deliver
flash[:notice] = "Set a notice if you want"
redirect_to root_url
else
# ... error messaging or actions here
end
end
Obviously, in UserMailer you can specify the html/text templates that will be used to display the confirmation message. confirmation_token should be a part of the #user model, you can use that to create the URL with the correct token:
<%= link_to 'Confirm your account', confirmation_url(#user, :confirmation_token => #user.confirmation_token) %>
I want to integrate Paypal within the Devise user registration process. What I want is to have a standard rails form based on the devise resource, that also has custom fields belonging to the user's model.
When a user fills in those fields and clicks on signup, it will be redirected to Paypal, when he clears from paypal and returns to our site then the user data must be created.
For the scenario where the user fill's out the paypal form but doesn't come back to our site, we have to keep record of user before redirecting to Paypal.
For this we can create a flag in user model and use Paypal IPN and when the user transaction notified, set that flag.
But in the case when the user is redirected to Paypal but doesn't complete the transaction, if the user returns to registration and signup again, our model should not throw error saying that the email entered already exists in the table.
How can we handle all these scenarios, is there any gem or plugin available to work with?
Here i am posting the detail code for performing the whole process.
registration_controller.rb
module Auth
class RegistrationController < Devise::RegistrationsController
include Auth::RegistrationHelper
def create
#user = User.new params[:user]
if #user.valid?
redirect_to get_subscribe_url(#user, request)
else
super
end
end
end
end
registration_helper.rb
module Auth::RegistrationHelper
def get_subscribe_url(user, request)
url = Rails.env == "production" ? "https://www.paypal.com/cgi-bin/webscr/?" : "https://www.sandbox.paypal.com/cgi-bin/webscr/?"
url + {
:ip => request.remote_ip,
:cmd => '_s-xclick',
:hosted_button_id => (Rails.env == "production" ? "ID_FOR_BUTTON" : "ID_FOR_BUTTON"),
:return_url => root_url,
:cancel_return_url => root_url,
:notify_url => payment_notifications_create_url,
:allow_note => true,
:custom => Base64.encode64("#{user.email}|#{user.organization_type_id}|#{user.password}")
}.to_query
end
end
payment_notification_controller.rb
class PaymentNotificationsController < ApplicationController
protect_from_forgery :except => [:create]
layout "single_column", :only => :show
def create
#notification = PaymentNotification.new
#notification.transaction_id = params[:ipn_track_id]
#notification.params = params
#notification.status = "paid"
#custom = Base64.decode64(params[:custom])
#custom = #custom.split("|")
#user = User.new
#user.email = #custom[0]
#user.organization_type_id = #custom[1].to_i
#user.password = #custom[2]
if #user.valid?
#user.save
#notification.user = #user
#notification.save
#user.send_confirmation_instructions
end
render :nothing => true
end
def show
end
end
I'm trying to build Facebook OAuth into my existing Authlogic login system. I have the OAuth part complete, and stored the facebook access_token. The problem I'm facing is to actually log the user in (create a session) without the user typing in their password.
#facebook's OAuth callback
def callback
access_token = client.web_server.get_access_token(params[:code], :redirect_uri => redirect_uri)
fb_user = JSON.parse(access_token.get('/me'))
#user = User.find_by_facebook_id(fb_user["id"]) || User.find_by_email(fb_user["email"]) || User.new
#user.update_attributes({
:facebook_id => fb_user["id"],
:first_name => fb_user["first_name"],
:last_name => fb_user["last_name"],
:gender => fb_user["gender"],
:email => fb_user["email"],
:timezone => fb_user["timezone"],
:locale => fb_user["locale"],
:facebook_url => fb_user["link"],
:facebook_access_token => access_token.token
}) #unless #user.updated_at < 2.days.ago
# TODO: set current_user
# Maybe something like this?
# #user_session = UserSession.new({
# :remember_me => true,
# :password =>"[FILTERED]",
# :email => email
# }).save
flash[:success] = "Welcome, #{#user.name}"
redirect_to :root
end
Nevermind I figured it out. It was in the README the whole time.
UserSession.new(#user, true) //true = persistent session