Hopp til innholdet

cjohansen.no

Validering på skinner

Skjemavalidering på klienten kan gjøre underverker for brukervennligheten av skjemaene dine. Desverre kan det også innføre ikke så hyggelig duplisering av logikk i applikasjonen når (langt på vei) de samme reglene for validering av data gjengis både i domenemodellen og i visningslaget. For dere som bruker Rails er jeg nå igang med en løsning på dette problemet.

validatious_on_rails

validatious_on_rails er en plugin til Rails som mapper valideringsreglene du setter på domeneobjektene dine direkte ut i skjemaer. Jeg har såvidt kommet igang, så dette er ikke klart til bruk med det helt første, men jeg har skrevet nok kode til å slutte at dette kommer til å funke, og det kommer til å funke bra.

Ett eksempel

Gitt at du har denne modellen:

class Person < ActiveRecord::Base
  validates_presence_of :name
  validates_presence_of :email
  validates_format_of :email, :with => /[EMAIL_REGEXP]/
end

...og denne template-koden:

<% form_for :person, :html => { :class => "validate" } do |f| %>
  <fieldset>
    <%= f.error_messages %>
    <div class="field">
      <%= f.label :name %>
      <%= f.text_field :name %>
    </div>
    <div class="field">
      <%= f.label :email %>
      <%= f.text_field :email %>
    </div>
  </fieldset>
<% end %>

...så ender du opp med denne HTML-en:

<form action="/people" method="post">
  <fieldset>
    <div class="field">
      <label for="person_name">Name</label>
      <input type="text" class="required" name="person[name]" id="person_name" value="" />
    </div>
    <div class="field">
      <label for="person_name">Email</label>
      <input type="text" class="required" name="person[email]" id="person_email" value="" />
    </div>
  </fieldset>
</form>

Med andre ord: dersom du har inkludert Validatious på denne siden har du plutselig ikke-påtrengende klientsidevalidering automagisk generert fra domenemodellen. Pretty spiffy!

Men hva med e-posten?

Den observante leser vil notere seg at eksempelet over ikke fikk med seg pattern-valideringa av e-poster. Validatious tilbyr per idag ingen validator som tar vilkårlige regulære uttrykk som parameter, og jeg syns heller ikke det er i Validatious' ånd å gjøre noe sånt. Derfor kan ikke validatious_on_rails mappe valideringene for validates_format_of helt uten videre.

Men fortvil ei, validerings-makroene til rails tar imot en hash med options, og denne kan vi putte hva vi vil i. Ved å sende med parameteret :name kan du fortelle validatious_on_rails hvilken validator du ønsker å bruke:

class Person < ActiveRecord::Base
  validates_presence_of :email
  validates_format_of :email, :with => /[...]/, :name => "email"
end

Og voila:

<input type="text" name="person[email]" id="person_email" class="required email" />

Hva med feltnavn?

En av styrkene til Validatious er dens evne til å tweake feilmeldinger uten å faktisk hardkode feilmeldinger for alle felt (selvom det også er mulig). For å bevare dette, pusser pluginen også opp label-metoden til Rails. Dersom det sendes inn en egen label-tekst (altså, du ønsker det autogenererte feltnavnet), og heller ikke sender med et title-attributt i options-hashen genererer pluginen en title med feltnavnet:

<%= f.label(:name, "Your name:") %>

resulterer i:

<label for="person_name" title="Name">Your name:</label>

mens

<%= f.label(:name, "Your name:", :title => "Your name") %>

resulterer i:

<label for="person_name" title="Your name">Your name:</label>

For å kunne støtte flerspråkelige sites skikkelig er det nødvendig å kunne unngå en sånn automatisk generereing av navn. Jeg er usikker på hvordan Rails 2.2 løser dette med autogenererte navn osv, men kanskje det allerede er løst der?

Arbeid under utvikling

Som nevnt innledningsvis er dette bare en start - det er mye igjen å gjøre. Foreløpig har jeg kun mappet opp disse validatorene:

enkelte av Rails validatorer lar seg ikke direkte oversette til Validatious, så jeg kommer nok også til å introdusere noen nye validatorer på den siden. Den største utfordringen blir å gi Validatious muligheten til å kjøre asynkrone valideringer for å kunne sjekke feks unikhet - for store tjenester der eksempelvis mange brukernavn er tatt vil dette være en fin måte å spare brukeren for litt tid på.

Andre begrensninger er

Og sikkert mye annet, jeg er så vidt igang.

Prøv den ut, gi feedback

Prøv gjerne med deres eksisterende applikasjoner for å få en følelse av hvordan dette fungerer. Kom gjerne med tilbakemeldinger på alle aspekter ved pluginen.

Installasjon

Enn så lenge har jeg basert meg på en annen plugin for å slå opp valideringene. Jeg er ikke helt fornøyd med denne avhengigheten, men enn så lenge så må den også installeres:

  1. ruby script/plugin install svn://rubyforge.org/var/svn/valirefl/validation_reflection/trunk
  2. ruby script/plugin install http://svn.cjohansen.no/rails/plugins/validatious_on_rails/trunk
  3. Last ned Validatious og inkluder den i app/views/layouts/application.html.erb

Dermed skal ting funke. Kom som sagt gjerne med tilbakemeldinger. Jeg kommer med oppdateringer når jeg kommer lengre med koden.

Muligens relatert

2006 - 2012 Christian Johansen Creative Commons Lisens