Rails. Save pass parameter from action to action - ruby-on-rails

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

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 - Show changes after PATCH

I would like to show the users which fields have been modified following his PUT/PATCH request
For example, I have a big "project" form, with several fields, but my user decided to only update the deadline and the project name. After he clicks the "save" button, I would like to show some message saying "You have successfully updated : name, deadline"
If it's possible, I would like some generic code that would detect the update action and infer the variable name. By generic I mean, I want to implement this in my ApplicationController, so I don't have to add code in every controller#update action
Let's look at this sample code from controllers/entreprise_controller.rb
def update
if #entreprise.update_attributes(entreprise_params)
redirect_to #entreprise, notice: "Entreprise éditée"
else
render 'edit'
end
end
Here's an idea of steps to reach my goal. Could you help me with each of these ? Or suggest a better approach ?
Detect that we are doing a CRUD update action, for example from the action name in the code, that should always be update (how can I read, from the code, the name of the action being executed ?)
Guess the variable name : here #entreprise, it can be inferred from the file for example (or maybe calling self.class and doing some regex ?)
Save the list of variables that are going to be updated (maybe some tricks involving before_action and after_action and dirty_tracking ? See my edit.)
Provide this list as a GET argument for the redirect to #entreprise (should be pretty straightforward)
Show this list to the user (this part is OK for me)
EDIT concerning Dirty Tracking
Mongoid already implements this. However the main problem is getting the intermediate variable before it is saved. Each controller instanciates the variable like #entreprise during a before_action callback. And if I add a before_action in my ApplicationController, it will fire before, so no variable is available yet. And as regards a possible after_action in ApplicationController, the doc says "Any persistence operation clears the changes." so it's dead already. I probably cannot get away without rewriting every controller ?
Dirty Tracking & controller in a nutshell :
prepend_before_action
before_action of ApplicationController
before_action of EntrepriseController (which includes set_entreprise, where the variable #entreprise is defined so as to proceed with update)
If we can get a callback to HERE, it would let us inspect the object for dirty tracking information, as the object exist in memory, we can use #entreprise.attributes=entreprise_params and look at the dirty info (where entreprise_params is the strong parameters for #entreprise)
action : on success, it will store the info in the DB, and we lose dirty tracking info
after_action

Landing Page for Age check in Rails App

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();

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.

Devise: how to store a particular location, not necessarily the last location?

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.

Resources