Landing Page for Age check in Rails App - ruby-on-rails

I have built a marketing site for an alcohol brand and I need to check the user's age by adding a landing page before they can enter the main site. What is the best way to tackle the form, submit and validation functionality inside my existing rails app?
Should I just create a raw html form and use javascript?

Add a before_action to ApplicationController that checks if the verification has already taken place (i.e. if it is stored in a cookie, then check for the cookie, etc):
class ApplicationController
before_action :check_age
def check_age
# check if the user has already confirmed their age.
end
...
end
If it doesn't find this, then redirect the user to a controller action that renders a page with the age check form (i.e. AgeVerificationController#new)
Upon submit, set the cookie (or whatever you are doing to store this data), and redirect the user back to the page they were intending to visit (or kick them off the site if they say they are under age!)
You will need to include a skip_before_action on the controller you are using to handle the rendering and submission of the form, i.e.
class AgeVerificationController < ApplicationController
skip_before_action :check_age
...
end`
Using before_action is sometimes a bit of an anti-pattern if you start using it to do a lot of complex stuff, but in this case it is a fairly simple way of doing what you are looking to do.

even if you use javascript,you will need to store the age of the guest to help him out next time for a better user experience.So i will suggest you to save it along with the ip-address to recognise the guest,if you are not storing a unique parameter for login(such as email,mobile number etc).
Once you have the table ready to store this details...you have many options such as:-
first option is to that,before submit get the age of guest using jquery validation and pass it to the controller using form and store it.Use ajax for form submission so that
you can validate other elements as well
second option is to let the user visit the page and show a modal window popup in the middle,after five seconds when page has loaded by using settimeout to call ajax which in turn will call a controller method to render js file which will call a modal such as $(".myModal").show(); or render your own view to get user details such as:
$('#myModal').find('.modal-body').html("<%= escape_javascript(render(:partial => 'users/get_details')) %>");
$('#myModal').modal();

Related

How do you make sure that after sign in the user completes the profile form first before they can use the rest of the website functions.

How do you make sure that after sign in the user completes the profile form first before they can use the rest of the website functions. I am trying to make sure that after the member has completed the sign up form and then completes there email confirmation with devise that when they sign in that when they are redirected to the new_member_profile_path(current_member) form that they stay on this page and that if they decide to go to a link and click that that they will automatically be redirected back to the complete your profile page with the notice before please complete your profile first. I have it set already once they have completed the form they will be redirected to their member's page. I have looked in multi-forms with wicked - I really feel that because I am still am a Novice rails developer that this would be unnecessary. I am thinking about putting an if clause in the application.html.erb where the site nav template is based and putting a clause with <% if current_member_profile.blank ? %> then redirect back to new_member_profile_path(current_member) with a flash notice tag written in the html file. I have tried this if clause but does not work - comes up as undefined method. Please could someone point me in the right direction or give me the simple solution of getting this idea to work. Thanks in advance ;)
There are various approaches to achieve what you're trying to do. Perhaps the cleanest with the least amount of code needed would be to first authenticate the user with Devise's own authenticate_user! filter and then check for a field that can only be there when the profile has been filled in.
# in user.rb
def has_completed_profile?
first_name.present?
end
# in application_controller.rb
before_action :authenticate_user!
before_action :require_user_profile
private
def require_user_profile
# nothing needs to be done if the profile was already filled in
return if user_signed_in? && current_user.has_completed_profile?
redirect_to edit_profile_url, alert: "Please complete your profile first!"
return false
end
Notice how I've extracted has_completed_profile? into the User model instead of putting the name check directly into the controller. This way, if you need to change the logic of what makes a profile "complete", you don't need to touch the controller at all ("complete profile" is a business concept, not a routing/HTTP concept and thus doesn't belong in the controller).
In controllers where you don't want the additional profile check – e.g. the controller where the user actually completes their profile, where they presumably need to be logged in but can't have a profile yet – you just skip the additional filter:
# in profiles_controller.rb
skip_before_action :require_user_profile
Side note: Over the years I've learned that it's best to keep things like profile data, address data, phone numbers and what not in a separate model and don't extend Devise's User model. This prevents various issues and keeps the already huge User model (Devise includes dozens of methods into it and turns it into a God Object as it is) a bit slimmer. And if you think about it, it also makes sense in terms of business logic: A user has_one profile, has_one address (or has_many addresses) etc.
Hope that's clear.
You can add a new method in the application_controller.rb
For eg
def current_member_profile
current_user.name.blank?
end
Check the params which should not be blank when creating a member profile. I have added 'name' here for example. if the params is blank, then it will redirect as you have specified in your application.html.erb
Instead for putting an if condition on the application.html.erb, You can use a before_action in your application_controller.
Something like this.
application_controller.rb:
before_action :check_for_profile_completion
def check_for_profile_completion
// your code of redirection to the page if the profile is incomplete
end
Also you can skip this action on controller which you don't wanna restrict user to go. Like
skip_before_action :check_for_profile_completion, only: [://actions you wanna skip seperated by comma]

Rails. Save pass parameter from action to action

For example, user visiting home with invitation link localhost:3000/home?invitation=invitation_token and I want to keep in params while user is browsing site till he visit registration page.
I know there is possibility to add params to link_to method but there is to many where I need to put this and it's not possible to predict user behavior.
But what I'm looking it's custom method what I will place in before_action what will check if there is params[:invitation] and pass it to next, unpredictable, method.
PS. I know that I can save to cookies, but this is not quite what I'm looking for.
You should save it in a session variable such as session[:invitation_token], otherwise you'll have to pass the param in every link. You can then use the variable directly such as:
before_action :check_token
def check_token
redirect_to registration_url unless session[:invitation_token]
end

Show page only once after sign up - Ruby on Rails

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

Rails : instance variables does not remain when reload page

I have a HTML page, in that page, there some options for User to select, this will affect how content will display.
I save those options by using instance variable in controller. For example :
class ShopController < ApplicationController
def index
#option1 = option1 # instance variable option1, contains some information on the form
end
end
In this page, I have a form for user input information. When user presses submit button, ShopControler will process those information. But at that time, when I check #option1 variable --> NIL. It means : this is an another instance of ShopController.
Please give me a solution for the problem that I meet, that I can save information, and can reuse although user has summit form.
Thanks :)
Have you thought about storing it in a session variable?
session[:option1] = option1
Then when you're done with it just do a
session.delete(:option1)
This will allow you to use it through multiple requests.
Typically when a user submits a form it will be routed to the create or update action. Unless you specifically have it routed to the index action your problem is most likely that you're not setting #option1 in the action the form is being submitted to.
If you find you are setting it in every action consider using a before_filter to set it.

Caching Pages in Rails based on attribute value?

I have a PagesController with a show action that currently looks like this:
class PagesController < ApplicationController
caches_page :show
def show
#page = Page.get_page(params)
end
end
My Pages model has a publish_datetime attribute, and the page isn't available to the public until the publish_datetime passes. Is there a way to specify in Ruby that the page should not be cached until the publish_datetime has passed?
Background:
Basically, there are people constantly in and out of the page editing the pages prior to their publication date, so that's one reason why I don't want the page to be cached. However, I figured out that I can expire the page on Update, but I'd prefer not to do that. The second reason is that I have a flag called has_been_published? that changes the way the page looks. If the page is accidentally cached before the publish_datetime, has_been_published? never gets called, and the page won't cache with the proper content.
Thanks for any help!
--Mark
You want to use action caching instead of page caching, so you can use a before_filter (or your auth stuff) to determine whether to render the full page or not.

Resources