- Notifications
You must be signed in to change notification settings - Fork2
Ruby gem for validating form data
License
readysteady/formeze
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Ruby gem for parsing and validating form data.
Most web applications built for end users will need to process form data.Registration forms, profile forms, checkout forms, contact forms, and formsfor adding/editing application specific data.
With formeze you can define form objects that explicitly define what yourapplication expects as input. This is more secure, and leads to much betterseparation of responsibilities, and also allows for implementing differentvalidation rules in different contexts.
Using Bundler:
$ bundle add formeze
Using RubyGems:
$ gem install formeze
Here is a minimal example, which defines a form with a single field:
require'formeze'classExampleForm <Formeze::Formfield:titleend
You can then parse and validate form data in Rails or Sinatra like this:
form=ExampleForm.new.parse(request)ifform.valid?# do something with form dataelse# display form.errors to userend
Formeze will exclude any parameters defined inFormeze.exclude
, which bydefault includes framework defined parameters like_method
,authenticity_token
,commit
, andutf8
.
If you prefer not to inherit from theFormeze::Form
class then you caninstead call theFormeze.setup
method on your classes like this:
classExampleFormFormeze.setup(self)field:titleend
Both styles of setup will include the formeze class methods and instancemethods but will otherwise leave the object untouched (i.e. you can defineyour own initialization logic).
Formeze distinguishes between validation errors (which are expected in thenormal running of your application), and key/value errors (which most likelyindicate either developer error, or form tampering). For the latter case,theparse
method that formeze provides will raise aFormeze::KeyError
or aFormeze::ValueError
exception if the structure of the form datadoes not match the field definitions.
After callingparse
you can check that the form is valid by calling thevalid?
method. If it isn't you can call theerrors
method which willreturn an array of error messages to display to the end user. You can alsouse theerrors_on?
anderrors_on
methods to check for and select errormessages specific to a single field.
By default fields are required (i.e. they cannot be blank), they are limitedto 64 characters, and they cannot contain newlines. These restrictions can beoverridden by setting various field options.
Defining a field without any options works well for a simple text input.If the default length limit is too big or too small you can override itby setting themaxlength
option. For example:
field:title,maxlength:200
Similarly there is aminlength
option for defining a minimum length:
field:password,minlength:8
Fields are required by default. Specify therequired
option if the fieldis optional. For example:
field:title,required:false
You might want to return a different value for blank fields, such as nil,zero, or a "null" object. Use theblank
option to specify this behaviour.For example:
field:title,required:false,blank:nil
If you are dealing with textareas (i.e. multiple lines of text) then you canset themultiline
option to allow newlines. For example:
field:description,maxlength:500,multiline:true
Error messages will include the field label, which by default is set to thefield name, capitalized, and with underscores replace by spaces. If you wantto override this, set thelabel
option. For example:
field:twitter,label:'Twitter Username'
If you want to validate that the field value matches a specific pattern youcan specify thepattern
option. This is useful for validating things withwell defined formats, like numbers. For example:
field:number,pattern:/\A[1-9]\d*\z/field:card_security_code,maxlength:5,pattern:/\A\d+\z/
If you want to validate that the field value belongs to a set of predefinedvalues then you can specify thevalues
option. This is useful for dealingwith input from select boxes, where the values are known upfront. For example:
field:card_expiry_month,values:(1..12).map(&:to_s)
Thevalues
option is also useful for checkboxes. Specify thekey_required
option to handle the case where the checkbox is unchecked. For example:
field:accept_terms,values:%w(true),key_required:false
Sometimes you'll have a field with multiple values, such as a multiple selectinput, or a set of checkboxes. For this case you can specify themultiple
option, for example:
field:colour,multiple:true,values:Colour.keys
Sometimes you'll only want the field to be defined if some condition is true.The condition may depend on the state of other form fields, or some externalstate accessible from the form object. You can do this by specifying eitherthedefined_if
ordefined_unless
options with a proc. Here's an exampleof using the defined_if option:
field:business_name,defined_if:->{@account.business?}
In this example thebusiness_name
field will only be defined and validatedfor business accounts. The proc is evaluated in the context of the form object,so has full access to instance variables and methods defined on the object.Here's an example of using the defined_unless option:
field:same_address,values:%w(true),key_required:falsefield:billing_address_line_one,defined_unless:->{same_address?}defsame_address?same_address =='true'end
In this example, thebilling_address_line_one
field will only be definedand validated if thesame_address
checkbox is checked.
Validation errors can be a frustrating experience for end users, so ideallywe want tobe liberal in what we accept,but at the same time ensuring that data is consistently formatted to make iteasy for us to process. Thescrub
option can be used to specify methods for"cleaning" input data before validation. For example:
field:postcode,scrub:[:strip,:squeeze,:upcase]
The input for this field will have leading/trailing whitespace stripped,double (or more) spaces squeezed, and the result upcased automatically.Custom scrub methods can be defined by adding a symbol/proc entry to theFormeze.scrub_methods
hash.
For file fields you can specify theaccept
andmaxsize
options, for example:
classExampleForm <Formeze::Formfield:image,accept:'image/jpeg,image/png',maxsize:1000end
For this to work you need to make sure your application includes themime-types gem, and that theform is submitted with the multipart/form-data mime type.
You may need additional validation logic beyond what the field optionsdescribed above provide, such as validating the format of a field withoutusing a regular expression, validating that two fields are equal etc.This can be accomplished using thevalidates
class method. Pass thename of the field to be validated, and a block/proc that encapsulatesthe validation logic. For example:
classExampleForm <Formeze::Formfield:emailvalidates:email, &EmailAddress.method(:valid?)end
If the block/proc takes no arguments then it will be evaluated in thescope of the form instance, which gives you access to the values of otherfields (and methods defined on the form). For example:
classExampleForm <Formeze::Formfield:passwordfield:password_confirmationvalidates:password_confirmationdopassword_confirmation ==passwordendend
Specify theif
option with a proc to peform the validation conditionally.Similar to thedefined_if
anddefined_unless
field options, the proc isevaluated in the scope of the form instance. For example:
classExampleForm <Formeze::Formfield:business_name,defined_if::business_account?field:vat_number,defined_if::business_account?validates:vat_number,if::business_account?do# ...enddefinitialize(account)@account=accountenddefbusiness_account?@account.business?endend
Specify theerror
option with a symbol to control which error the validationgenerates. The I18n integration described below can be used to specify theerror message used, both for errors that are explicitly specified using thisoption, and the default "invalid" error. For example:
classExampleForm <Formeze::Formfield:emailfield:passwordfield:password_confirmationvalidates:email, &EmailAddress.method(:valid?)validates:password_confirmation,error::does_not_matchdopassword_confirmation ==passwordendend
The error for the email field validation would include the value of theformeze.errors.invalid
I18n key, defaulting to "is invalid" if the I18nkey does not exist. The error for the password_confirmation field validationwould include the value of theformeze.errors.does_not_match
I18n key.
Formeze integrates with thei18n gemso that you can define custom error messages and field labels within yourlocales (useful both for localization, and when working with designers).
Here is an example of how you would change the "required" error message:
# config/locales/en.ymlen:formeze:errors:required:"cannot be blank"
Error messages defined in this way apply globally to all Formeze forms.
You can also change error messages on a per field basis, for example:
# config/locales/en.ymlen:ExampleForm:errors:comments:required:'are required'
Here is an example of how to define a custom label for "first_name" fields:
# config/locales/en.ymlen:formeze:labels:first_name:"First Name"
Labels defined in this way apply globally to all Formeze forms, but can beoverridden using the label field option which will take precedence.
About
Ruby gem for validating form data