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.