Al D
Al D

Reputation: 667

Rails send a form to server for validation before commit

I've a fairly detailed Rails form (<%= form_for(@pay_line) do |f| %>) that takes multiple values input by the user.

I need to check a number of things on this form before I commit the values to the database (such as the net pay is not a negative etc.). I'd normally use jQuery but some of the calculations are very detailed and rely on join queries in the controller etc. so as far as I can see, it's not really an option.

I'm wondering how I should go about this. Is there a way to send the form to the database for processing before committing and if certain things fail, send the values back with a message saying certain things need to be adjusted by the user? Or is there another option I can use?

Hopefully I've explained it properly but if I haven't, let me know and I'll give more details.

Thanks for looking

Upvotes: 0

Views: 650

Answers (2)

lcoq
lcoq

Reputation: 10726

You can achieve this using ActiveRecord::Validations.

It allows you to run some validations on a model before committing the changes to the database, and access to the errors when the model is invalid:

class Person < ActiveRecord::Base
  validates :name, presence: true
end

>> p = Person.new
# => #<Person id: nil, name: nil>
>> p.errors.messages
# => {}

>> p.valid?
# => false
>> p.errors.messages
# => {name:["can't be blank"]}

Assuming you want to edit a Person, save its changes or display its errors when the changes are invalid, you could do something like this:

# config/routes.rb
YourApp.routes.draw do
  resources :persons, only: [ :edit, :update ]
  # This generates requests :
  #   GET '/persons/1/edit' (used to display the form)
  #   POST '/persons/1 (used to save the changes)
end

# app/controllers/persons_controller.rb
class PersonsController < ApplicationController
  def edit
    @person = Person.find(params[:id])
    # used to display the edit form
  end
  def update
    @person = Person.find(params[:id])
    if @person.update_attributes(params[:person])
      # the changes are valid, here we simply redirect
      # to the home page
      redirect_to(root_path)
    else
      # the changes are invalid, we display the form
      # again
      render :edit
  end
end

The edit view will display both the person form and its possible errors :

<%# app/views/persons/edit.html.erb %>
<% if @person.errors.any? %>
  <ul>
    <% @person.errors.full_messages.each do |error_message| %>
      <li><%= error_message %></li>
    <% end %>
  </ul>
<% end %>
<%= form_for(@person) do %>
  <%# your custom form fields %>  
<% end %>  

Notice the example above generates page reload when submitting the form.

To prevent this, you might use Ajax requests to send the form in JS to the Rails server. In this case, the Rails server could render JSON instead of HTML.

Upvotes: 1

Sean
Sean

Reputation: 333

You can use a custom validator for more complex validation.

To validate net pay:

class MyValidator < ActiveModel::Validator
  def validate(record)
    unless record.net_pay > 0
      record.errors[:name] << 'Net pay must be greater than 0!'
    end
  end
end

class Person
  include ActiveModel::Validations
  validates_with MyValidator
end

Upvotes: 1

Related Questions