This is a feature I struggled with for quite awhile, so I thought I’d share my solution. The code is actually pretty simple once I got it figured out. Hopefully it will save somebody else some headaches.
So here’s what we’re doing
To create an easy on-boarding process, I’ve put a New List form on the front page of Favsi.com. However, creating a list requires the user to be authenticated, so I needed to create a way to retain the user’s New List form data through the authentication/registration process, and then post it. Here’s a screenshot of the front page:
The flow would go like this
- User goes to the front page.
- User fills out the New List form and presses the Create List button.
- If the user is not logged in, they are prompted to login or register.
- User logs in/registers using standard authentication or using the Facebook/Twitter Connect flow.
- Once logged in/registered, the form data from Step 2 gets submitted and the user is redirected to view their published list.
After much Googling, StackOverflowing, and asking Portland Ruby folks there seemed to be 2 possible approaches:
- Once the form is submitted, carry the form data through the login process in hidden fields then submit it once logged in.
- Write the form data to the user’s session then retrieve and submit it once logged in.
Since Favsi offers Facebook and Twitter authentication (which routes the users off of Favsi.com) option 2 was the only choice.
So let’s get to the code (comments inline)
# lists_controller.rb class ListsController < ApplicationController # Make sure not to filter 'create' as we'll be handling that with our redirect before_filter :authenticate_user!, :except => [:show, :index, :create] ... def create # Check to see if the user is registered/logged in if current_user.nil? # Store the form data in the session so we can retrieve it after login session[:list] = params # Redirect the user to register/login redirect_to new_user_registration_path else # If the user is already logged in, proceed as normal @list = current_user.lists.new(params[:list]) respond_to do |format| if @list.save format.html { redirect_to(user_list_path(@list.user, @list), :notice => 'Sweet, your list has been created.') } format.xml { render :xml => @list, :status => :created, :location => @list } else format.html { render :action => "new" } format.xml { render :xml => @list.errors, :status => :unprocessable_entity } end end end end
Devise has a built in function for redirecting after the user logs in. We’ll be using this redirect to check if there is a temporary list saved in the session and, if so, save it as a new list.
# application_controller.rb class ApplicationController < ActionController::Base protect_from_forgery def after_sign_in_path_for(resource) # save list if there is a temp_list in the session if session[:list].present? # save list @list = current_user.lists.create(session[:list]["list"]) # clear session session[:list] = nil #redirect flash[:notice] = "Sweet, logged in. Nice list, btw :)" user_list_path(@list.user, @list) else #if there is not temp list in the session proceed as normal super end end private end
That’s it! Works like butter. You can test it on the front page of Favsi.
muyiwaoyeniyi
I removed my previous comment about having an error. I messed up the syntax.Now it really works like butter. Thanks a lot…many thanks.Taiwo
Muhammad Nuzaihan Bin Kamal Luddin
How if,
I want the keep the user session intact with the email and password fields and then the user fills up another form with the name, address and phone number before sending it to the registrations controller in devise?
Thanks!
Steven Zeiler
Thank you! This is exactly what I was looking for.
utku
I am getting ActiveModel::ForbiddenAttributesError when I did this.
The error is in this line:
# Save the pool
@pool = current_user.pools.create(session[:pool][“pool”])
.
To resolve this I tried adding:
private
def pool_params
params.require(:pool).permit(:title, :description, :user_id)
end
into pools controller and also application controller but same error just is there all the time :( What could be the reason and solution to this?
utku
i solved it :)
the solution was this:
new_attributes = session[:pool].require(:pool).permit(:title, :description)
@pool = current_user.pools.create(new_attributes)
Justin Thiele
Glad to hear you got it figured out, utku!
Melissa
Spent all day looking for a solution, and this was perfect! Thanks!
Chris
Exactly what i was looking for, thanks you for this!
carl
Worked perfectly for me! Many thanks