Reputation: 1625
I have a simple form on a website where a user enters a mailing address.
I have a service which can validate this address and return various responses, either Success, Suspect, or Invalid, as well as return the full and most complete zip code for that address. If the response is "Success", then I will save it to the db. If the response is "Suspect", then I will update the zip field and ask them to confirm. If the response is "Invalid" then I will return an error message asking them to contact us in person.
I'm trying to set up my rails create action such that it makes a call to my service (for example http:/addresssValidator.com) and I want to inform the user if they have a valid address or not, and update the zip with the suggested zip code.
Looking for address validation in rails however, seems to only give me APIs for using the built in error and validation system in rails and not how to return my own custom results to the form.
How can I do this?
Below is my code:
def create
@valid = validate_address
@address = Address.new(address_params)
if @valid
if @address.save
redirect_to "/survey/success"
else
p @address.errors
respond_to do |format|
format.json {render json: @address.errors}
format.html {render "/survey/failure"}
end
end
else
##//Display errors
end
end
def validate_address
@api_key = "my_api_key"
HTTParty.post("http://addressValidator.com",
{
:body => [
"StreetAddress" => params[:address][:address_line_2] + " " + params[:address][:address_line_1],
"City" => params[:address][:city],
"PostalCode" => params[:address][:zip],
"State" => params[:address][:state],
"CountryCode" => params[:address][:country],
"Locale" => "en" ].to_json,
:APIKey => @api_key ,
:headers => { 'Content-Type' => 'application/json', 'Accept' => 'application/json'}
})
return false;
##//return actual results from validator
end
Upvotes: 5
Views: 4049
Reputation: 102036
In Rails you add errors to your models. To add an error you would do something like this:
if @address.country == "Sealand"
@address.errors[:country] << ["we don't ship there"]
end
In Rails forms are just are just simple form-builders bound to a model which create HTML. They don't actually have a role in validation besides displaying errors.
Rails lets you create custom validator classes and HTTParty is made to extend classes.
Lets mosh them together:
class AddressValidator < ActiveModel::Validator
include HTTParty
base_uri 'addressValidator.com'
format :json
def validate(address)
response = self.post('/',
# Note that I am just guessing here.
body: {
"StreetAddress" => address.street_address,
"City" => address.city,
"PostalCode" => address.zip,
"State" => address.state,
"CountryCode" => address.country
}
)
if response.success?
# bind the errors to the model
unless response["StreetAddress"] == "valid"
record.errors[:street_address] << response["StreetAddress"]
end
else
e = response.response
logger.warn "Failed to remotely validate Address. #{ e.message }"
address.errors[:base] << "Failed to remotely validate!"
end
end
end
Of course you will need to adapt this to the actual response from the API and your model. This is just a starting point demonstrating the coarse strokes.
def Address < ActiveRecord::Base
validates_with AddressValidator
# ...
end
Upvotes: 4
Reputation: 1445
If you want to add a custom error to a specific field:
@address.errors[:FIELD_NAME] << "Custom Error Message"
that way the error is added to the instance that you have, and will be shown in the form itself as the other errors appear.
if you just want to display an error, you can add it to the flash[:error]
like this:
flash[:error] = "Invalid address"
if you want the error to move to the next method (like if you will use redirect after it), or:
flash.now[:error] = "Invalid address"
if you want the error to be available only in current action. as @illusionist said in comment.
and in the html code, check if it exists, and if so, print it:
<% if flash[:error] %>
<%= flash[:error] %>
<% end %>
in both ways, you can add the error from @valid
.
If you want to store the new zip, add @address.zip = @valid.zip
. That way it will show it in the field in the form.
Upvotes: 5