How do I create a two-step form in rails? - ruby-on-rails

I have a question for rails. I'm creating a form for user to register. What I want to do is that after the user press "Submit" button I want to redirect the user to another page which shows all the information from the form filled by the user just now (read-only).
This is my controller
class PermitsController < ApplicationController
before_action :set_permit, only: [:show, :destroy]
def index
#permits = Permit.all
end
def new
#permits = Permit.new
end
def create
#permits = current_user.permits.build(permit_params)
if #permits.save
redirect_to invoice_path
else
render 'new'
end
end
def destroy
Permit.destroy_all(user_id: current_user)
respond_to do |format|
format.html { redirect_to root_path, notice: 'Permit was successfully canceled.' }
format.json { head :no_content }
end
end
def invoice
#permits = current_user.permits(permit_params)
end
def show
#user = User.find(params[:id])
#permits = #user.permits.paginate(permit_params)
end
def update
#permits = Permit.where(user_id: current_user).take
respond_to do |format|
if #permits.update(permit_params)
format.html { redirect_to root_path}
flash[:success] = "Permit successfully updated"
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_permit
#permits = Permit.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def permit_params
params.require(:permit).permit(:vehicle_type, :name, :studentid, :department, :carplate, :duration, :permitstart, :permitend)
end
end
This is the form filled by user
<% provide(:title, 'New Permit') %>
<h1>Permit Application</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#permits) do |f| %>
<%= f.label :"Vehicle" %>
<%= f.text_field :vehicle_type, class: 'form-control' %>
<%= f.label :"License Plate" %>
<%= f.text_field :carplate, class: 'form-control' %>
<%= f.label :"Student ID" %>
<%= f.text_field :studentid, class: 'form-control' %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :"Department of applicant" %>
<%= f.text_field :department, class: 'form-control' %>
<%= f.label :permit_start %>
<%= f.date_select :permitstart, class: 'form-control' %>
<%= f.label :permit_end %>
<%= f.date_select :permitend, class: 'form-control' %>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
</div>
</div>

You could add an additional action between new and create.
# config/routes.rb
resources :permit do
collection do
post :confirm
end
end
The reason that we use POST even if the route does not create a resource is that we don't want to pass any user info in the request URL.
class PermitsController < ApplicationController
# POST /permits/confirm
def confirm
#fields = %i[vehicle_type, carplate, studentid, name, department, permitstart, permitend]
#permit = current_user.permits.build(permit_params)
render :new and return unless #permit.valid?
end
end
render :new and return unless #permit.valid? shortcuts the process and renders the :new form again if the input is not valid in the first place.
Since we are using POST we need a form for both the new.html.erb and confirm.html.erb all duplicating all those inputs would not be great so lets extract them to a partial:
<% # /views/permits/_inputs.html.erb %>
<%
input_options ||= {}
input_options[:class] ||= 'form-control'
%>
<%= f.label :"Vehicle" %>
<%= f.text_field :vehicle_type, input_options%>
<%= f.label :"License Plate" %>
<%= f.text_field :carplate, input_options %>
<%= f.label :"Student ID" %>
<%= f.text_field :studentid, input_options %>
<%= f.label :name %>
<%= f.text_field :name, input_options %>
<%= f.label :"Department of applicant" %>
<%= f.text_field :department, input_options %>
<%= f.label :permit_start %>
<%= f.date_select :permitstart, input_options %>
<%= f.label :permit_end %>
<%= f.date_select :permitend, input_options %>
So lets point the new.html.erb form so that it submits to /permits/confirm:
<% provide(:title, 'New Permit') %>
<h1>Permit Application</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#permits, url: '/permits/confirm_permits_path') do |f| %>
<% render partial: :inputs %>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
</div>
</div>
And create a /views/permits/confirm.html.erb view:
<% provide(:title, 'Confirm Permit application') %>
<h1>Confirm Permit application</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#permits) do |f| %>
<% render partial: :inputs, input_options: { readonly: 'readonly' } %>
<% end %>
</div>
</div>

Related

Keep getting "Param is missing or the value is empty"

I keep getting the error mentioned above, even though my form object matches my controller object (most people who had this problem had mixed their objects up in similar questions). What exactly am I doing wrong here?
My code is below:
<!-- The form is here -->
<%= form_for(#user), url: {action: "/users/signup"}, html: {class: "signup_form"} do |f| %>
<%= label_tag(:firstname, "Firstname: ") %>
<%= f.text_field :firstname %>
<%= label_tag(:lastname, "Lastname: ") %>
<%= f.text_field :lastname %>
<%= label_tag(:username, "Username: ") %>
<%= f.text_field :username %>
<%= label_tag(:email, "Email: ") %>
<%= f.text_field :email %>
<%= label_tag(:password, "Password") %>
<%= f.password_field :password %>
<%= f.submit "Create Account" %>
<% end %>
And here's the controller:
class UsersController < ApplicationController
def create
#user = User.new(user_params)
#user.save
redirect_to #user
end
private
def user_params
params.require(:user).permit(:firstname, :lastname, :username,
:email, :password)
end
end
Would really appreciate some help and sorry if I missed something silly here, thanks in advance.
users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, success: 'Thanks for signing up!' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
end
users/_form.html.erb
<%= form_for(#user) do |f| %>
<div class="field">
<%= f.label :first_name, "First name" %><br>
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name, "Last name" %><br>
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :email, "Email" %><br>
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password, "Password" %><br>
<%= f.password_field :password %>
</div>
<div class="actions">
<%= f.submit "Sign Up" %>
</div>
<% end %>
Why do you have url: {action: "/users/signup"} in the form? It is much simpler if you do the following:
routes.rb
Rails.application.routes.draw do
resources :user
end
views/users/_form.html.erb
<%= form_for(#user), html: {class: "signup_form"} do |f| %>
controllers/users_controller.rb (add the following)
class UsersController < ApplicationController
def new
#user = User.new
end
end
If you do it like this, form_for will automatically detect whether or not the #user object has been saved in the database, and will route the form to the create or update method respectively.
I general I don't reccommend altering the standard RESTful routes unless absolutley necessary. A user is not likely going to look at yoursite.com/users/new in the URL and be upset or confused.

Rails 4: can't update current user

I'm trying to update some specific values for current_user but I have had no luck with it. The values do not save and the page doesn't get redirected anywhere whatsoever. Here's the code for user controller in update
def update
#user = current_user
respond_to do |format|
if #user.update_attributes(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit, notice: 'Update unsuccessful' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def user_params
params.require(:user).permit(:username, :password, :password_confirmation, :email, :weight, :height, :age, :activity_level, :goal, :calorie_goal, :fat_goal, :carb_goal, :protein_goal, :fiber_goal, :sugar_goal)
end
I tried to use params[:user] or params[:current_user] instead of user_params but with no luck.. here's html
<h2>Set Up Your Profile</h2>
<% #user = current_user %>
<%= form_for(#user) do |f| %>
current user is <%= current_user.username %>
<div class="field">
<%= f.label :weight %><br>
<%= f.text_field :weight %>
</div>
<div class="field">
<%= f.label :height %><br>
<%= f.text_field :height %>
</div>
<div class="field">
<%= f.label :age %><br>
<%= f.number_field :age %>
</div>
<div class="field">
<%= f.label :activity_level %><br>
<%= f.number_field :activity_level %>
</div>
<div class="field">
<%= f.label :goal %><br>
<%= f.number_field :goal %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
here I tried form_for(current_user) as well but didn't work, too... Any ideas what's wrong here?

DRY controller .valid? for create and update using simple_form

So I've got these views:
new.html.erb
<div class="booyah-box col-xs-10 col-xs-offset-1">
<h1>Expose Your Hidden Gem</h1>
<%= simple_form_for #place do |f| %>
<%= f.input :name, error: "Name is mandatory" %>
<%= f.input :address %>
<%= f.input :description %>
<br />
<%= f.submit 'Create', class: 'btn btn-primary' %>
<% end %>
</div>
edit.html.erb
<div class="booyah-box col-xs-10 col-xs-offset-1">
<h1>Edit Your Place</h1>
<%= simple_form_for #place do |f| %>
<%= f.input :name %>
<%= f.input :address %>
<%= f.input :description %>
<br />
<%= f.submit 'Update', class: 'btn btn-primary' %>
<% end %>
</div>
this model:
Place.rb
class Place < ActiveRecord::Base
belongs_to :user
has_many :comments, dependent: :destroy
has_many :photos
geocoded_by :address
after_validation :geocode
validates :name, presence: true
validates :address, presence: true
validates :description, presence: true
end
And finally, places_controller.rb (only showing create and update)
def create
#place = current_user.places.create(place_params)
if #place.save
redirect_to root_path
else
render :new
end
end
def update
#place = Place.find(params[:id])
if #place.user != current_user
return render text: 'Not Allowed', status: :forbidden
end
#place.update_attributes(place_params)
if #place.save
redirect_to root_path
else
render :edit
end
end
But, I'm trying to think DRY and want to know if there is a better way to do a validation for name address and description presence without having the same identical code in both the create and update portions of my controller? I feel like I should just be writing it once...
First, you can refactor your views to use the following structure:
# new.html.erb
<div class="booyah-box col-xs-10 col-xs-offset-1">
<h1>Expose Your Hidden Gem</h1>
<%= render 'form' %>
</div>
# edit.html.erb
<div class="booyah-box col-xs-10 col-xs-offset-1">
<h1>Edit Your Place</h1>
<%= render 'form' %>
</div>
# _form.html.erb
<%= simple_form_for #place do |f| %>
<%= f.input :name %>
<%= f.input :address %>
<%= f.input :description %>
<br />
<% submit_label = #place.new_record? ? 'Create' : 'Update' %>
<%= f.submit submit_label, class: 'btn btn-primary' %>
<% end %>
And then in your controllers you could refactor to:
def create
#place = current_user.places.new(place_params)
if #place.save
redirect_to root_path
else
render :new
end
end
def update
#place = current_user.places.find(params[:id])
#place.attributes = place_params
if #place.save
redirect_to root_path
else
render :edit
end
end

Ruby On Rails Update failed still

I have try many things but still failed, i want to implement a edit and update action here.
Below is my code
home controller:
class HomeController < ApplicationController
def index
#inputs = Person.all
end
def new
#input = Person.new
end
def create
#input = Person.new(input_params)
respond_to do |x|
if #input.save
x.html {redirect_to :action => 'index'}
else
x.html {render :action => 'new'}
end
end
end
def show
#input = Person.find(params[:id])
end
def edit
#input = Person.find(params[:id])
end
def update
#input = Person.find(params[:id])
respond_to do |x|
if #input.update(input_params)
x.html {redirect_to :action => 'index'}
else
x.html {render :edit}
end
end
end
private
def input_params
params.require(:inputs).permit(:name, :weight, :height, :color, :age)
end
end
edit.html.erb
<h1>Editing Data</h1>
<%= render 'form' %>
<%= link_to 'Show', home_path %> |
<%= link_to 'Back', home_index_path %>
form.html.erb:
<%= form_for :#input do |person| %>
<div class="field">
<%= person.label :name %><br>
<%= person.text_field :name %>
</div>
<div class="field">
<%= person.label :weight %><br>
<%= person.number_field :weight %>
</div>
<div class="field">
<%= person.label :height %><br>
<%= person.number_field :height %>
</div>
<div class="field">
<%= person.label :color %><br>
<%= person.text_field :color %>
</div>
<div class="field">
<%= person.label :age %><br>
<%= person.number_field :age %>
</div>
<div class="actions">
<%= person.submit %>
</div>
<% end %>
Routes are correct, i can lead me to the edit page, however, it shows,
first problem, edit with no data pops up
New updated
You should use form_for instead of form_tag,
<%= form_for #input do |x| %>
...
and then (depending on what #input actually is!)
<%= x.text_field :age %>
It looks like you are not binding your form to your method.
http://guides.rubyonrails.org/form_helpers.html#binding-a-form-to-an-object
gives an overview, but I'd suggest something like this for your edit:
<%= form_for #input do |f| %>
<%= render 'form', f: f %>
<%= f.submit "Update" %>
<% end %>
and in your partial - which should be _form.html.erb
<div class="field">
<p><label for = "input_name">Name</label>:
<%= f.text_field :name %>
</div>
etc.. Now assuming you have set your routes correctly, it will go back to your update method. If you have not set up your routes in the way rails expects, then you should use:
<%= form_for #article, url: **your_update_path** do |f| %>
Just add the routes path that points to your update method, when you run rake routes.

Ruby Incorrect link generation redirect_to products_path(#product) generate /products.1 instead of /products/1

I'm trying to add a reviews on my single product page. But when I click Submit - It takes me to the /products.1 page, instead of /products/1
class CommentsController < ApplicationController
def create
#product = Product.find(params[:product_id])
#comment = #product.comments.new(comment_params)
#comment.user = current_user
#comment.save
redirect_to products_path(#product)
end
def destroy
end
private
def comment_params
params.require(:comment).permit(:user_id, :body, :rating)
end
end
and the comment.html.erb
<div class="row">
<div class="col-sm-6">
<% if signed_in? %>
<h4>Add a review:</h4>
<%= form_for([#product, #product.comments.build]) do |f| %>
<p>
<%= f.label :body, "Comment" %><br>
<%= f.text_area :body, class: "form-control" %>
</p>
<p>
<%= f.label :rating %><br>
<%= f.text_field :rating, class: "rating form-control" %>
</p>
<p>
<%= f.submit "Submit", class: "btn" %>
</p>
<% end %>
<% end %>
</div>
</div>
Try redirect_to #product instead of redirect_to products_path(#product).
Did you check your routes.rb under config? Try running rake routes in the terminal and you can debug from there.

Resources