The Power of Declarative Validation

You could write code that tests each property’s value as it arrives, and there may be times when you need to do that, but Rails offers a simpler approach that works for the vast majority of cases: declarative validation. (You can find the complete example shown here in ch07/guestbook005.)

Instead of checking to see if a value is present, for instance, you can just write:

# the name is mandatory
  validates_presence_of :name

The validates_presence_of declaration activates Rails’ internal validation tools, which can automatically block the addition of a record that’s missing a name and report an error to the user, as shown in Figure 7-3.

Failing a simple validation

Figure 7-3. Failing a simple validation

How did the model reach through the controller, all the way into the view, and make that happen? It’s worth walking back through once to trace the path Rails took. Example 7-3 shows the HTML that generated those messages.

Example 7-3. Model errors reported in HTML from the view

<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this
person from being saved</h2><p>There were problems with the following
fields:</p><ul><li>Name can't be blank</li></ul></div>

<form action="/people" class="new_person" id="new_person" method="post"><div 
style="margin:0;padding:0"><input name="authenticity_token" type="hidden" 
value="b23eb784af45413f54bf73d49ea6eccd8115f3ee" /></div>
  <p>
    <b>Name</b><br />
    <div class="fieldWithErrors"><input id="person_name" name="person[name]" 
size="30" type="text" value="" /></div>
  </p>

The first piece, the errorExplanation div, came from this line of code in the view (or partial):

<%= error_messages_for :person %>

Rails inserted the fieldWithErrors div around the name field through the usual field creation method in the view (or partial):

<%= f.text_field :name %>

This kind of automatic error presentation is another reason it’s a good idea to use Rails’ built-in methods for creating fields, rather than handcoding your own HTML in them.

The controller also took part in the action. If you look back at the PeopleController’s create method, you’ll see:

# POST /people
  # POST /people.xml
  def create
    @person = Person.new(params[:person])

    respond_to do |format|
      if @person.save
        flash[:notice] = 'Person was successfully created.'
        format.html { redirect_to(@person) }
        format.xml  { render :xml => @person, :status => :created, :location => @person }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @person.errors, :status =>
:unprocessable_entity }
      end
    end
  end

If the controller has an error, @person.save will fail, returning false. If the request is for HTML, the controller will render a new copy of the form for creating a new person entry. All of the error information will pass through to that view automatically. If it is an XML request, it will also report back the errors.

Note

One major benefit of putting validation in the model is that your validation will apply to any effort to change your data—whether it came from users over the Web, from programs accessing your application through REST-based web services, or from something you built into the program yourself.

Now that we’ve seen how the errors flow out from the model to the view, it’s time to examine how to set up the validation declarations that make it all happen.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset