Ruby on Rails - Session variable on form submit - ruby-on-rails

I have an application which requires visitors to fill out a form and then it redirects to a second page. The client does not want to require visitors sign up to view this page, only to fill out the form.
The way I am attempting to do this is by creating a session variable when the page is visited and then checking to see if the variable exists before the next page is accessible. Is it possible to delay the creation of the session variable until the submit action is processed? If so what would that look like?
Also, can anyone think of a better way to do this? Sorry, this is probably a dumb question.

The session cookie would be declared after the first submit.
I presume the first submit will load up a controller#action in which you'll then redirect to the next page. Just set the session in there:
#app/views/forms/1.html.erb
<%= form_tag form_1_submit_path do %>
...
<% end %>
This will allow you to do the following:
#app/controllers/forms_controller.rb
class FormsController < ApplicationController
def form_1_submit
session[:value] = params[:value]
redirect_to form_2
end
end
Thus you'll have session[:value] all set and ready to use on the next form:
#app/views/forms/2.html.erb
<%= form_tag .... do %>
<%= text_field_tag :test, value: session[:value] %>
<% end %>

Related

would it be ok to create an instantiate an object in another controller?

I have a controller for customer. In the new action, I redirect to another page, which belong to the pages controller
class CustomersController < ApplicationController
def new
redirect_to register_path
end
Would it be possible to create the object in the registration action like this?
class PagesController < ApplicationController
def registration
#customer = Customer.new
end
end
I believe the setup is something like this: you have models in your application for a Customer and, say, an Agent. Your website users register as either and the desire is to have a single HTML page (URL) with both options available. They choose which one they are and submit some fields, say name/email/password. To keep it simple, without bothering with JavaScript to hide things behind tabs, you have something like:
**Customer**
Name: ___________
Email: __________
Password: _______
[Submit]
**Agent**
Name: ___________
Email: __________
Password: _______
[Submit]
You have a few options here to avoid your guilty feeling in the Rails controllers:
Go heavy client-side JavaScript. Don't have the new actions on the controllers. The JavaScript creates the page elements. The create action becomes a JSON API endpoint, thereby avoiding the problem in the Ruby application. This is obviously a significant architectural deviation from where I think you are today.
Use a little bit of JavaScript to dynamically load the correct 'partial' into the DOM when the user switches between the options. Avoids the underlying problem in the question by effectively separating the 'pages' out to the two controllers. The Pages→registration action does not need to set any instance variables for the view. The JavaScript deals with the partial loading. (see 'link_to' and the 'remote' option)
Don't include both forms in the same HTML page, just default to one, say the Customer one, and provide a link to navigate to the Agent one, e.g. a link in a tab, or a plain link like "Not a Customer? Register as an Agent." In this scenario, you have a neat mapping to the Ruby MVC design, each of the pages are just the new action of its relevant controller. The downside is a page load to change between the two options. This is the simplest, plainest choice … if you can get the boss to agree to the UX. PS: if you are using turbolinks, then the 'feel' of this option in the browser will be not far from option (2).
Stick to your design
Keep in mind that you will have difficultly dealing with error conditions and messages with option (4). You can do it, but the code won't be simple or easy to maintain.
If option (4) is a must, one simplification can be the create actions on each of the controllers rendering their own new in case of an error. If you submit the 'Agent' form from your starting page, with errors, to the Agents→create action, that action finishes with a render 'new' to show the user the Agents→new page. No 'customer' form is visible. You could then add a sprinkle of option (3) in there with a "Not an Agent? Register as a Customer." link under the form. Doing this greatly simplifies your error handling.
Which then leads to a suggestion for your original problem. Cheat. Don't have an #customer instance variable for the new actions (or the registration action). Use partials for the customer and agent forms, and pass in a new object to form_for, e.g.
pages/registration.html.erb
<%= render 'customers/new_form' %>
<%= render 'agents/new_form' %>
customers/new.html.erb
<%= render 'customers/new_form' %>
customers/_new_form.html.erb
<% form_for Customer.new do |f| %>
<%# include the inputs shared with the edit action %>
<%= render 'fields', f %>
<%= f.submit %>
<% end %>
customers/_fields.html.erb
<%# 'f' is one of the locals passed to the partial %>
<% f.input_field :name %>
<% f.email_field :email %>
<% f.password_field :password %>
customers/edit.html.erb
<% form_form #customer do |f| %>
<%= render 'fields', f %>
<%= f.submit %>
<% end %>
… then you would follow the same pattern for:
agents/new.html.erb
agents/_new_form.html.erb
agents/_fields.html.erb
agents/edit.html.erb

Rails "form_for" action, how redirect to a different path depending of kind of user

I am using Devise as my authentication on a Rails app.
The User form works fine, but I want it to redirect to a different path depending on where the person starts on the site.
So all people (customers, contractors) are Users. But if you sign up to apply to be a new Contractor I want to send you to the new application form. If you are a customer you need to go to a different page with a different form.
I am new(again) to Rails and can not figure out how to do this. Is it something I can change in "form_for" directly in the view or something that needs to be done in the controller.
UPDATE:
<%= form_for(resource, as: resource_name, url: new_contrator_path(resource_name)) do |f| %>
ERROR:
undefined method `new_contrator_path' for #<#:0x007f88834bec28>
I am sure I am screwing up something in a controller...
2nd UPDATE
I am using this with 'scout_app' as the hidden field
<%= f.hidden_field :type, value: "scout_app" %>
This is what I have in the new user form but I can't get it to pass the attribute to the User. It always has NIL
You can use the url parameter in form_for.
For example:
<%= form_for(#post, url: custom_path) do |f| %>
...
<% end %>
You can override default sign_in method of devise and redirect as per your requirement in your application_controller.rb file
def after_sign_in_path_for(resource)
# your code
end

Instance Variables in a Partial for Sign-Ups

I am currently working on a website that will require users to sign-up, in order to perform various tasks. However, I am having some trouble with sign-ups.
I have a partial named _form.html.erb, which is rendered in application.html.erb (so that it appears on every page users navigate to) as a fade-in, fade-out modal form (I am using Twitter Bootstrap). What do I need to do, in order to pass an instance variable to this partial and have a user created in the database, once the user presses the submit button? Do I need to create a new method in application_controller.rb and a new user model?
Thank you for the help!
Note: I've read this link (http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials), but did not get much out of it.
I would assign a local variable when rendering the partial that stores the user object.
layouts/application.html.erb
<%= render "users/form", :user => User.new %>
users/new.html.erb
<%= render "form", :user => #user %>
Using this technique your form would reference the local variable.
<%= form_for user do |f| %>
<!-- form fields here -->
<% end %>

Holding off on create action

I want to have a form that anyone can fill out, but must be logged in to submit it - if not, put the process on hold until they do.
My thought process is if someone comes across the form, it checks if they are logged in, if not the user can still fill it out, but instead prompted to log in or sign up as opposed to "Submit". If they click on either link (log in/sign up) I want it to save the form data, most likely to the session, have them log in/sign up, and then have the computer check to see if there is a saved form, and if so display a confirmation like screen, where the newly registered user can accept it.
I've posted come code below that I thought would work, but it isn't - and I was thinking that knowing rails, theres probably some convention out the to do this much faster and easier!
And I don't believe the way that I am passing the form data around is correct, so if anyone can correct me there that would be great!
View
<%= form_for :comment, :url => {:action => 'create'} %>
form fields here
<% if current_user %>
<%= f.submit "Submit" %>
<% else %>
<%= link_to "Log In", save_to_session_and_log_in_path(:comment => :comment) %> or
<%= link_to "Sign Up", save_to_session_and_sign_up_path(:comment => :comment) %>
<% end %>
Controller
def save_to_session_and_log_in_path
session[:temp_comment] = Comment.new(params[:comment])
redirect_to log_in_path
end
def save_to_session_and_sign_up_path
session[:temp_comment] = Comment.new(params[:comment])
redirect_to sign_up_path
end
User* Controller
def create
#Normal create action, under the redirect:
if session[:temp_comment]
redirect_to confirm_comment
else
redirect_to users_home_page
end
end
The error I am receiving is:
ActiveRecord::RecordNotFound in CommentsController#show
Couldn't find Comment with id=save_to_session_and_log_in
Rails.root: scrubbed
Application Trace | Framework Trace | Full Trace
app/controllers/comments_controller.rb:87:in `show'
Request
Parameters:
{"comment"=>"comment"
"id"=>"save_to_session_and_log_in"}
I've tried tweaking it every which way but it still keeps getting me here so I am unable to test if any of my code is working
What are your CommentsController#create and #show action? About your error, could you paste the rake routes result for the save_to_session_and_log_in_path and the save_to_session_and_sign_up_path methods? Since you don't have an id at that moment, you should set them as collection routes.
--
The way I'd do it, though, is submitting the form to different controllers that will handle each scenario. That way, your CommentsController will be for logged in users and you can have a TemporaryCommentsController that will take care of comments made by guests.
--
Also, depending on the comment's field, I don't know if it's a great idea to store them in the session. You could probably store a tmp_comment_id in the session and recover that from the DB. Also, delete all records with a cron-job. (This is a problem only when "the comment is big and 'hard' to serialize" though).

Action form_for -> show

URL : /evaluations
I have made a form to select a specific item (a period)
class EvaluationsController < ApplicationController
def index
#periods = Period.all
end
My form :
<% form_for XXXXX do %>
<%= collection_select(:period, :period_id, #periods, :id, :fullname) %>
<%= submit_tag("Valider") %>
<% end %>
I would like the form to go to /evaluations/3 when submited (if the selected period is 3).
When I go manually to /evaluations/3 it works like a charm but I really don't know how to write the form_for to go the right url by submitting the form.
Simple way
Submit period ID to process data, and then redirect to action, which handles
evaluations/:id with :id as parameters.
redirect_to <youraction>(:period => #id)
This should do the trick.
Not so simple way
If you want to change something dynamically on your page after data was submitted - call method and respond with javascript
respond_to do |format|
format.js
end
In javascript response you can put whatever you want - simple redirects or script, which will change page dynamically. It's up to you.
Hope it helps.
you need to use some javascript to update the action of the form
$('#period_period_id').change(function() {
$('form').attr('action', '/evaluations/' + this.value);
})

Resources