The Booking sample app demonstrates:
Here are the contents of the app:
booking/app/
models # Structs and validation.
booking.go
hotel.go
user.go
controllers
init.go # Register all of the interceptors.
gorp.go # A plugin for setting up Gorp, creating tables, and managing transactions.
app.go # "Login" and "Register new user" pages
hotels.go # Hotel searching and booking
views
...
This app uses go-sqlite3, which wraps the C library.
Install Homebrew ( http://mxcl.github.com/homebrew/ ):
> ruby <(curl -fsSkL raw.github.com/mxcl/homebrew/go)
Install pkg-config and sqlite3:
> brew install pkgconfig sqlite3
`sudo apt-get install sqlite3 libsqlite3-dev`
Once you have SQLite installed, it should be possible to run the booking app as usual:
$ revel run github.com/robfig/revel/samples/booking
app/controllers/gorp.go defines GorpPlugin
, which is a plugin that does a couple things:
app/controllers/init.go registers the interceptors that run before every action:
func init() { revel.OnAppStart(Init) revel.InterceptMethod((*GorpController).Begin, revel.BEFORE) revel.InterceptMethod(Application.AddUser, revel.BEFORE) revel.InterceptMethod(Hotels.checkUser, revel.BEFORE) revel.InterceptMethod((*GorpController).Commit, revel.AFTER) revel.InterceptMethod((*GorpController).Rollback, revel.FINALLY) }
As an example, checkUser
looks up the username in the session and redirects
the user to log in if they are not already.
func (c Hotels) checkUser() revel.Result { if user := c.connected(); user == nil { c.Flash.Error("Please log in first") return c.Redirect(Application.Index) } return nil }
Check out the user management code in app.go
The booking app does quite a bit of validation.
For example, here is the routine to validate a booking, from models/booking.go:
func (booking Booking) Validate(v *revel.Validation) { v.Required(booking.User) v.Required(booking.Hotel) v.Required(booking.CheckInDate) v.Required(booking.CheckOutDate) v.Match(b.CardNumber, regexp.MustCompile(`\d{16}`)). Message("Credit card number must be numeric and 16 digits") v.Check(booking.NameOnCard, revel.Required{}, revel.MinSize{3}, revel.MaxSize{70}, ) }
Revel applies the validation and records errors using the name of the
validated variable (unless overridden). For example, booking.CheckInDate
is
required; if it evaluates to the zero date, Revel stores a ValidationError
in
the validation context under the key “booking.CheckInDate”.
Subsequently, the Hotels/Book.html template can easily access them using the field helper:
{{with $field := field "booking.CheckInDate" .}} <p class="{{$field.ErrorClass}}"> <strong>Check In Date:</strong> <input type="text" size="10" name="{{$field.Name}}" class="datepicker" value="{{$field.Flash}}"> * <span class="error">{{$field.Error}}</span> </p> {{end}}
The field template helper looks for errors in the validation context, using the field name as the key.