user1010101
user1010101

Reputation: 1658

Proper way to handle a form when user provides no inputs

I have a simple application that will ask user to enter their start and end address and once they do that they can hit submit and get a list of the next 3 buses/trains to their destinations. However I am not able to handle the case where the user does not enter anything at all and hits submit button.

Here is the code of the simple form

   <%= form_tag("/welcome/index", method: "post") do %>
  <div class ="input-group">
  <label>Current Location</label>
  <%= text_field_tag("address", params['address'], :class => 'form-control') %>
</div><br/>
<div class ="input-group">
  <label>Destination Location</label>
  <%= text_field_tag("destaddress", params['destaddress'], :class => 'form-control') %>
  </div>


  <p>
    <br/>
<%= submit_tag "", :value => "Find Buses", :class => "btn btn-default" %>  </p>

<% end %>

Here is my controller where i capture user's input and run my logic to give the list of buses.

class WelcomeController < ApplicationController
  # displays the form, so change the name of the form you have now to new.html.erb
  def new
  end

  # the form will pass to this action to perform logic on longitude and latitude
  def create
    curAddress = params[:address]
    destAddress = params[:destaddress]



    #2 close stops to current location
    @currentList = Stop.by_distance(:origin => curAddress).limit(2)

    if @currentList.length == 0
      flash[:error] = "Somethig is wrong"
    end
    #2 closest stops to destination location
    @destList = Stop.by_distance(:origin => destAddress).limit(2)

    @startIds = Array.new
    2.times do |i|
      @startIds.push(@currentList[i].id)
    end

    @endIds = Array.new
    2.times do |i|
      @endIds.push(@destList[i].id)
    end


    @currentStop = Stop.closest(:origin => curAddress)
    @destinationStop = Stop.closest(:origin => destAddress)



         @timeNow = Time.now.in_time_zone("EST") + 1.hour
    @finalTime = @timeNow.strftime("%H:%M:%S")

    startStopId = @currentStop.first.id
    endStopId = @destinationStop.first.id

     #update it based on succeed
    @cStop = Stop.find(startStopId)
    @dStop = Stop.find(endStopId)




    testMethod(startStopId,endStopId)  


    render :index
  end

Above what i do is basically take user's input and then try to use a gem called Geokit to find the two closest stops for some given address by user and store their ids in @currentList and @destList

So obviously if the user has not given any input than those 2 lists should be empty right. So using that logic I tried this

 if @currentList.length == 0
      flash[:error] = "Somethig is wrong"
    end

However I am not able to handle the case where user gives no input. So i was wondering how to handle it? Ideally I want to display a message on the form saying "No inputs entered" so user will retry to enter some input and then hit submit. I am extremely new to ruby on rails , for instance I know in java i could throw exception or something.

Upvotes: 0

Views: 104

Answers (2)

Sharvy Ahmed
Sharvy Ahmed

Reputation: 7405

First of all validations can be checked in front-end as well as in back-end.

You can use html5 required to make the input field mandatory and no one can proceed unless they write something.

<%= text_field_tag("address", params['address'], :class => 'form-control'), :required => true %>

For back-end validation, you can check if the fields are not nil like this:

if curAddress && destAddress
  # Do your work here ...
end

By the way, you will have to refactor the code a lot. A simple refactoring could be declaring a private method to get the nearest location ids by distance like this:

private
def nearest_by_distance(address, n)
  Stop.by_distance(:origin => address).limit(n).pluck(:id)
end

Then in your create action you can do:

current_address = params[:address]
destination_address = params[:destaddress]

@start_from_location_ids = nearest_by_distance(current_address, 2)
@end_to_location_ids = nearest_by_distance(destination_address, 2)

Hope you got the idea?

Upvotes: 1

Clark
Clark

Reputation: 616

Inside of def create ...

if params[:address].blank? || params[:destaddress].blank? # Checks if it is nil or = ""
  flash[:address_error] = "No address entered"
  render 'new' and return # render new shows the form again, return makes sure we
                          # don't do anything else in the action
                          # you can also do redirect_to, but this will be a little
                          # faster since you have no logic the new action
end

You should do this early in the action, so you don't waste time doing other things in the action.

As Sharvy Ahmed mentioned front-end validation is an option as well, and a good idea. An alternative to the HTML5 method he showed is JQuery, which rails uses by default. That might looks something like this.

$('form').submit(function() {  //When a form is submitted...
  $('input').each(function() { //Check each input...
    if ($(this).val() == "") { //To see if it is empty...
      alert("Missing address");//Say that it is
      return false;            //Don't submit the form
    }
  });
  return;                      //If we made it this far, all is well, submit the form
});

However you should not rely on client side validation, as a user can manually go to the url, bypassing the page with the validation.

Upvotes: 1

Related Questions