I am trying to create the user registration views and model on my website but I am having a small issue :
I am using devise and omniauth to get the facebook connect features working and it works,
But I want my facebook users when they sign in the first time to create their password,
That is also working, I redirect them to the filled sign up form and they only have to enter their password. But I want them to go to a second "sign_up form" named /views/registrations/new_facebook.html.erb where they can only enter their password and I will also add some other information,
I created the correct view and tested it but I have no idea how to create the correct routes to bypass Devise default
match '/facebook' => 'registrations#new', :as => 'new_facebook_user_registration'
I believe the issue is with match because that's what's not recognised,
If anyone can help me that would be great thanks,
I added my controller code for omniauth :
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def all
user = User.from_omniauth(request.env["omniauth.auth"])
if user.persisted?
flash[:success] = "Welcome back"
sign_in_and_redirect user
else
session["devise.user_attributes"] = user.attributes
redirect_to new_facebook_user_registration_url
end
end
alias_method :facebook, :all
end
How can I make the redirect_to new_facebook_user_registration_url actually work ?
devise_scope :user do
match "registrations/new_facebook" => "registrations#new_facebook"
end
That's the solution I copied in the registrations controller the new method and named it new_facebook and now everything is working as expected !
I think the issue is that you're not overriding the devise method that redirects to that path. Also according to the devise docs your routes should be set up with a "devise_for" call.
Here's the wiki page describing how to do what you are asking to do, although you may need a bit of custom logic to deal with cases that aren't facebook signups.
https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-up-(registration)
Some example code from that page:
class RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
'/an/example/path'
end
end
and the one for routes:
devise_for :users, :controllers => { :registrations => "registrations" }
Related
Using
ruby 1.9.3p448
Rails 3.2.13
devise (2.2.3)
When a user follows the link from a password reset email or a unlock account email (devise :recoverable, :lockable) they are redirected first to sign in. I have seen in the logs, this is a 302.
I have modified
~/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/actionpack-3.2.13/lib/action_controller/metal/redirecting.rb
so that the redirect method has the following added to the top:
File.open("/home/myname/fooblah.txt", 'a'){|f| f.puts(caller()); f.puts "########"}
So to see where redirect_to is being called. In the caller() chain, no code from the application is calling redirect_to. So I am wondering if there is some bug or quirk which causes this redirect.
Currently a user has to go back to the link in the email and hit it a second time
Update
In .rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/devise-2.2.3/app/controllers/devise/unlocks_controller.rb
# GET /resource/unlock?unlock_token=abcdef
def show
self.resource = resource_class.unlock_access_by_token(params[:unlock_token])
if resource.errors.empty?
set_flash_message :notice, :unlocked if is_navigational_format?
respond_with_navigational(resource){ redirect_to after_unlock_path_for(resource) }
else
respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render :new }
end
end
protected
# The path used after unlocking the resource
def after_unlock_path_for(resource)
new_session_path(resource)
end
... so its default to redirect to root path? But devise.yml says:
unlocked: 'Your account was successfully unlocked. You are now signed in.'
This seems to be an incongruency in the Devise gem...
I guess you have added :authenticate_user! in your application controller and have overridden devise's controllers .
If this is the case you have to add skip_before_filter :authenticate_user! to overridden controllers action
I got a question will trying to use omniauth-facebook with devise
I followed this railscast video(just substitute twitter with facebook) and was able to get it work.
However, I would like to customize my routes a little bit, so this is what I did:
config/routes.rb
devise_for :users, path: 'accounts',
controllers: { omniauth_callbacks: "omniauth_callbacks" },
path_names: { sign_in: "login", sign_out: "logout", sign_up: "signup" }
app/controllers/omniauth_callbacks_controller.rb
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def all
user = User.from_omniauth(request.env["omniauth.auth"])
if user.persisted?
flash.notice = "Successfully signed in via #{request.env["omniauth.auth"].provider}!"
sign_in_and_redirect user
else
session["devise.user_attributes"] = user.attributes
redirect_to new_user_registration_url
end
end
alias_method :facebook, :all
end
as I expected, in my url "users/..." was changed to "accounts/...", but when I tried to login via facebook, I got this error:
Routing Error
No route matches [GET] "/users/auth/facebook/callback"
after play around with it, I got around it by adding this line:
config/routes.rb
get '/users/auth/facebook/callback', to: redirect('/accounts/auth/facebook/callback')
It works fine now, but I think there must be better solution.
Is there any way to change the returned callback url from /users/auth/facebook/callback to /accounts/auth/facebook/callback ???
Thanks!
Problems Solved, I forgot to set window.location in Javascript code.
After I changed my window.location, it's working fine
I have setup devise on a site and now the client just wants to be able to use 1 master password and not allow anyone else to create accounts. I removed the create account links from the login page and I also extended my RegistrationsController to look like this.
class CustomRegistrationsController < Devise::RegistrationsController
# used to override normal create behavior
def create
redirect_to user_session_path
end
# used to override normal new behavior. Redirects user back to the login page
def new
redirect_to user_session_path
end
end
Then in my routes file I have
devise_for :users, :path => '', :path_names => { :sign_in => 'login', :sign_out => 'logout'}, :controllers => { :registrations => "custom_registrations"}
Now I'm trying to find a way where I can either hardcode a master username and password or come up with a better approach to this.
This is by no means an elegant solution, but you could simply use a migration (or the database seed file, if the database is still new enough to be generated that way) to create a single User object with the desired login info, and add a validation on User that returns false if there's already an existing User.
Say a user clicks a link to a page that is protected. They are then redirected to a sign in screen where they can log in. If they do, then are successfully redirected to that page. But if they don't have an account they have to sign up. This is where things get tricky because I'm doing an email confirmation.
By clicking a link it creates a new session can I can't automatically redirect the user to that protected page. I'm trying to change this by putting in a reference to the redirect inside the confirmation link. I would like to do:
<%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #resource.confirmation_token, :redirect_to => stored_location_for(#resource)) %>
But I can't figure out how to get access to stored_location_for (or if that is even the right location to get). It is defined in Devise::Controllers::Helpers, but it is an instance method so I can't do Devise::Controllers::Helpers.stored_location_for(…).
How do I get access to stored_location_for or what is the better way of doing this?
My goal is to do that and then in my custom ConfirmationsController define:
def show
if params[:redirect_to]
session["user_return_to"] = params[:redirect_to]
end
super
end
That should work right?
I figured it out. I'm not sure if this changes with the update Devise did yesterday in making Devise::Mailer put most of its functionality into a module. (See the code and ticket for more information).
Basically it boils down to not being able to access the session inside of a mailer view. Therefore you have to pass the redirect as a variable. Devise uses an after_create method on your resource (User in my case) which then sends the confirmation email. This meant I couldn't just pass the session variable directly to the mailer. Thus I feel like this is a pretty nasty work-around in order to get this functionality, but here is the code:
To get the redirect_to variable into the mailer you have to add a variable to the user, thus:
class User < ActiveRecord::Base
…
attr_accessor :return_to
…
end
Then you have to set that variable when you create the user for the first time.
I already had a custom controller setup for registration. (See Devise' Readme on how to set this up, or see #ramc's answer for direction). But it was relatively easy to do this part, I just added it to the parameters and let the rest take care of itself.
class RegistrationsController < Devise::RegistrationsController
def create
params[:user][:return_to] = session[:user_return_to] if session[:user_return_to]
…
super
end
end
Now the user has a variable return_to which is set. We just need to access that in the confirmation_instructions email. I've already rewritten part of confirmation_instructions.html.erb so inside there I just added:
<% if #resource.return_to %>
<%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #resource.confirmation_token, :redirect_to => #resource.return_to) %>
<% else %>
<%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #resource.confirmation_token) %>
<% end %>
(For those who are new to this, #resource is the variable Devise uses to define your user).
Now once the user clicks on that link we need to redirect them. #ramc's before filter works well for this:
class ConfirmationsController < Devise::ConfirmationsController
before_filter :set_redirect_location, :only => :show
def set_redirect_location
session[:user_return_to] = params[:redirect_to] if params[:redirect_to]
end
end
That will take care of the case where a new user goes to a protected page then signs up, clicks on the confirmation link and is properly redirected to the protected page.
Now we just need to take care of the case where a user does the above, but instead of clicking on the link, they try to go back to the protected page. In this case they are asked to sign-up/sign-in. They sign-in and then are asked to confirm their email and are given the option of resending the confirmation email. They put in their email and now we need to put the redirect_to variable in that new confirmation email.
To do this we need to modify the ConfirmationController, similarly to how we did the RegistrationController. This time we need to modify the create method. The way it works out of the box is to call a class method on the user called send_confirmation_instructions. We want to rewrite that method so we can pass the return_to variable into it.
class ConfirmationsController < Devise::ConfirmationsController
def create
self.resource = resource_class.send_confirmation_instructions(params[resource_name],session[:user_return_to])
if resource.errors.empty?
set_flash_message(:notice, :send_instructions) if is_navigational_format?
respond_with resource, :location => after_resending_confirmation_instructions_path_for(resource_name)
else
respond_with_navigational(resource){ render_with_scope :new }
end
end
end
The only thing different than what comes with Devise is that first line of create, we pass two variables in. Now we need to rewrite that method:
class User < ActiveRecord::Base
def self.send_confirmation_instructions(attributes={},redirect=nil)
confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
confirmable.return_to = redirect if confirmable.persisted?
confirmable.resend_confirmation_token if confirmable.persisted?
confirmable
end
end
confirmable becomes an instance of User (the current user based on email). So we just need to set return_to.
That's it.
Looking at the way stored_location_for has been implemented in lib/devise/controllers/helpers.rb
def stored_location_for(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
session.delete("#{scope}_return_to")
end
It is possible to otherwise access it using session['user_return_to']. In your case, you would lose that session object because when the user clicks on the link from the confirmation mail, it might be a new session that is spawned.
You can implement whatever you have suggested as a before filter:
class Users::ConfirmationsController < Devise::ConfirmationsController
before_filter :set_redirect_location, :only => :show
def set_redirect_location
session["user_return_to"] = params[:redirect_to] if params[:redirect_to]
end
end
In addition to this, you will have to modify the route to make devise call your controller instead of its own confirmation controller.
devise_for :users,
:controllers => { :confirmations => 'users/confirmations'}
Hope this helps :)
Note: The code snippets are not complete and only contain relevant details.
From what I can see from the comments in the devise source code, all you need to do is implement the following in your registrations_controller.rb:
def after_inactive_sign_up_path_for(resource_or_scope)
session["user_return_to"]
end
I'm doing a simple user with profile application. User registers and
are automatically logged in. Works fine so far. Now, I'd like to
create a profile after a successful registration and redirect the user
to his/her profile.
I have a User model and controller. Devise also created the
registration controller. I installed the gem. I copied over the devise
files and I plan to override the create action.
First, whatever I edit in registrations_controller.rb nothing
changes.
class Devise::RegistrationsController < ApplicationController
prepend_before_filter :require_no_authentication, :only =>
[ :new, :create, :cancel ]
prepend_before_filter :authenticate_scope!, :only =>
[:edit, :update, :destroy]
include Devise::Controllers::InternalHelpers
Secondly, how to insert the profile creation step?
def create
build_resource
if resource.save
if resource.active?
set_flash_message :notice, :signed_up
sign_in_and_redirect(resource_name, resource)
else
set_flash_message :notice, :inactive_signed_up, :reason =>
resource.inactive_message.to_s
expire_session_data_after_sign_in!
redirect_to after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords(resource)
render_with_scope :new
end
end
I was thinking to add
current_user.create_profile under is resource.active?
How would you guys tackle that issue?
First, Please format your post and use <code> blocks for the snippets. That way it becomes very readable.
Coming to your problem:
Devise by default sign ins and redirects to application root_path, after registration.
If you wish to redirect to some other path you can specify it in a couple of ways.
One is to specify root_path for your devise reource. So in your case it will be
match '/user/profile/new' => 'profiles#new', :as => 'user_root'
This will redirect you to profile#new every time you login.
To prevent redirecting to profile#new each time you can add a before_filter on profile#new to check if profile exists and redirect to some other page, say dashboards, if profile exists.
Here is the link showing how to change redirect_path for devise:
https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-in