Using Rails 3.
In usual app, a form only appears if the user is logged in. Then in the controller, we will run another check on authentication before we save the new record.
However, I want to show the form to everyone regardless if he's logged in. When the visitor submits the form with attachment, etc., it will then check if the user is logged in. If he isn't, then redirect him to login/signup page, and when he's completed that, only then the new record is saved.
I understand this can be achieved with the create and save, but can someone elaborate more on how to achieve this in a clearer explanation?
User submits form
Controller sees user is not logged in
Controller persists submitted form to the database
Controller sets cookie with id of new object
Controller redirects to login
User logs in
Controller retrieves persisted form information from database
Controller assigns object to user
Run a periodic job to clean old unclaimed form data.
Well, in the view you'd show the form always without any kind of login check. The tricky part here is to save the data the user has sent before he's redirected to the login.
One solution would be to save the post data in a cookie and then redirect the user to the same page after the login, triggering the create again
On the controller you'd do exactly as you described:
class ThingController
def create
if user_logged_in?
if cookie[:stuff]
# create the stuff from cookie and remove it
else
# create the stuff
end
else
# redirect him to login with a callback to this same place
end
end
end
Related
In addition to the normal login route (UserSessionsController.create) I have a special route in a different controller that does a bunch of other stuff including creating a new user and I would like to be able to log in as that newly created user. To run this route you have to already be logged in, so I would like to destroy the current session and create a new session with the new user.
Pulling from the existing routes that work I have put together this code:
#user_session = UserSession.find
#user_session.destroy
#user_session = UserSession.new({email: new_user.email, password: new_user.password})
#user_session.save!
redirect_to value_chain_hierarchy_path(new_business_entity)
Because the user was just created, we still have access to their password.
Stepping through this code with a debugger I can see that the current session gets destroyed (has a nil user) and when I save the new session and ask for its user I get the new user back, but when the page loads I'm still logged in as the previous user.
I'm pretty stumped. I'm guessing it has something to do with updating the session cookies or something like that. But I don't know what to try next.
I have an app that is using Devise, I would like that after a user signs up, they are directed to a specific page, this page calls an API and saves the value from the API, I need this page to only be accessible or available after a user completes the sign-up form and clicks submit, and is then redirected to this page.
I do not want this page or URL accessible any other way but after sign-up, as the API will send a new value if accessed again. How can I accomplish this?
Once a user signs up they will be redirected to the page calling the API:
def after_sign_up_path_for(resource)
api_call_path ##path that can only be accessed after sign_up
end
The API is called and the response from the JSON data is automatically saved to the database once the page is opened, if the page gets opened again a new JSON response will be received with new data, which is what I would like to avoid.
So in a nutshell, my question is how can I restrict access to a specific path, and only make that path accessible if a user completes the sign-up form (devise) OR is there a way that I can run the code from the controller using a callback/filter after the user is created through the User model?
I was just busy with something similar. You do not need to direct the user to a page to run the code, you can just run the code that needs to be run after the user logs in the first time.
You need to create a Session Controller, and create a conditional statement that checks if the user has logged in previously:
#config/routes.rb
devise_for :users, controllers: { sessions: "sessions" }
#app/controllers/sessions_controller.rb
class SessionsController < Devise::SessionsController
def after_sign_in_path_for(resource)
if resource.sign_in_count == 1
##Do something awesome
else
root_path
end
end
end
As Emmanuel advised you can check futher info on the Devise Controllers.
Let's call the moment between after sign_up and showing the specific page - state A. So in the specific page controller you need to know - is the user in state A. You can achieve it by
1) saving to db (server side) that user is in state A after sign up and resetting state after showing specific page (you can do resetting triggered by client side to guarantee that page is showed).
2) saving to cookies (client side) after sign up then do as above.
Second solution is more clean in my opinion, but I do not know how strict is the rule to show only once
You can customize devise users controller by issuing
rails generate devise:controllers [scope]
Then customise UsersController such that after user is saved you can call your api code there
eg
def create
#user = ....
if #user.save
#user.call_api_method()
else
......
end
end
For more information check Configuring controllers
My signup works like this:
User takes a quiz, which is submitted as a form and stored in the session
User registers for the site using either Facebook or a classic username/password
Upon successful registration, the quiz results are persisted with the user
I thought of making my signup start with a separate controller action in step #1, persisting the results to session, then creating a post-registration callback for devise to save the results in step #3.
What's the best approach to implement this? Will the session be overwritten in step #2?
You approach is correct.
You should store the quiz result in a specific session hash, like in session[:quiz] that won't be overriden when the user sucessfully login using devise registration.
Then you may override the devise registration controller and add the quiz result in the User with the other information
class Users::RegistrationsController < Devise::RegistrationsController
def create
super
#find user and set the quiz to persist
end
end
I'm wondering if I'm asking too much of Devise. I'd like to allow a visitor to fill out a form and then but then be required to sign up when they press the "submit" button. That's the easy part. My problem is that once the user is redirected to the sign up form and they fill it out, I can't get them redirected back to the original form so that that form can be submitted (but now with the user ID).
I've played around with the "after_sign_in_path_for(resource)" method in the application controller, but my problem is that after signup, the request.referer isn't the original form, it's the signup form. I thought about using a before_filter :store_location callback, but then I realized that it'll store the most recent location, which is the url for the signup form.
How do I set up devise that original form as the correct location to render after sign up?
P.S. This question comes from a related one, located here.
Try this make 2 method in ApplicationController which saves
the current url to the session, and another that redirects to the stored
url (which should have a default in case it can't find it). Then, in
pages which i want to bookmark for returning to (you might not want
someone to get sent back to some pages), then save the url.
EG in application.rb
def store_location
session['saved_location'] = request.request_uri
end
def redirect_to_back_or_default(default)
if session['saved_location'].nil?
redirect_to default
else
redirect_to session['return-to']
session['saved_location'] = nil
end
end
Then, in a page that you want the user to be able to go back to:
Then, just call
redirect_to_back_or_default('enter your chosen default url here, depending on context')
in after_sign_in_path_for(resource_or_scope) to send someone back.
Using restful_authentication and
before_filter :login_required, :only=> [:create]
on controller:
Is it possible to store data from form, and after user logged in, continue with 'create'?
So i mean:
User logged off and he see Somecontroller#new
Then he fill in the form
Then he press "Save"
As we have login_required, user now has to login.
After login the 'create' action continues, and user should be redirected to some path (which set on create action)
If no, how such system ca be done?
The main idea is smooth flow — so unregister user don't have to signup first, he can do that during "create" action.
Many thanks!
You can store the data with YAML in the session hash. After they login, you can then redirect back to the form action and retrieve values from session, or create the resource, or do whatever you need to do.