Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

executable file 3520 lines (2603 sloc) 54.336 kb
#LyX 2.0 created this file. For more info see http://www.lyx.org/
\lyxformat 413
\begin_document
\begin_header
\textclass hobo
\use_default_options true
\master hobo.lyx
\begin_modules
logicalmkup
\end_modules
\maintain_unincluded_children false
\language english
\language_package default
\inputencoding auto
\fontencoding global
\font_roman default
\font_sans default
\font_typewriter default
\font_default_family default
\use_non_tex_fonts false
\font_sc false
\font_osf false
\font_sf_scale 100
\font_tt_scale 100
\graphics default
\default_output_format default
\output_sync 0
\bibtex_command default
\index_command default
\float_placement H
\paperfontsize default
\spacing single
\use_hyperref false
\papersize default
\use_geometry false
\use_amsmath 1
\use_esint 1
\use_mhchem 1
\use_mathdots 1
\cite_engine basic
\use_bibtopic false
\use_indices false
\paperorientation portrait
\suppress_date false
\use_refstyle 1
\boxbgcolor #e6e6e6
\index Index
\shortcut idx
\color #008000
\end_index
\secnumdepth -1
\tocdepth 2
\paragraph_separation skip
\defskip smallskip
\quotes_language english
\papercolumns 1
\papersides 1
\paperpagestyle default
\tracking_changes false
\output_changes false
\html_math_output 0
\html_css_as_file 0
\html_be_strict false
\end_header
\begin_body
\begin_layout Chapter
Chapter 9
\begin_inset Newline newline
\end_inset
HOBO CONTROLLERS AND ROUTING
\end_layout
\begin_layout Standard
This chapter of the Hobo Manual describes Hobo’s
\begin_inset Flex Emph
status collapsed
\begin_layout Plain Layout
Model Controller
\end_layout
\end_inset
and automatic routing.
In a very simple Hobo app, you hardly need to touch the automatically generated
controllers, or even think about routing.
As an app gets more interesting though, you’ll quickly need to know how
to customize things.
The down-side of having almost no code at all in the controllers is that
there’s nothing there to tweak.
Don’t worry though, Hobo’s controllers have been built with Customization
in mind.
The things you will tweak commonly are extremely easy, and full Customization
is not hard at all.
\end_layout
\begin_layout Section
Introduction
\end_layout
\begin_layout Standard
Here’s a typical controller in a Hobo app.
In fact this is unchanged from the code generated by the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_model_controller
\end_layout
\end_inset
generator:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
class AdvertsController < ActiveRecord::Base
\end_layout
\begin_layout Code
hobo_model_controller
\end_layout
\begin_layout Code
auto_actions :all
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
The
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_model_controller
\end_layout
\end_inset
declaration just does include
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
Hobo::ModelController
\end_layout
\end_inset
, and gives you a chance to indicate which model this controller looks after.
E.g., you can do
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_model_controller Advert
\end_layout
\end_inset
By default the model to use is inferred from the name of the controller.
\end_layout
\begin_layout Subsection*
Selecting the automatic actions
\end_layout
\begin_layout Standard
Hobo provides working implementations of the full set of standard REST actions
that are familiar from Rails:
\end_layout
\begin_layout Itemize
index
\end_layout
\begin_layout Itemize
show
\end_layout
\begin_layout Itemize
new
\end_layout
\begin_layout Itemize
create
\end_layout
\begin_layout Itemize
edit
\end_layout
\begin_layout Itemize
update
\end_layout
\begin_layout Itemize
destroy
\end_layout
\begin_layout Standard
A controller that declares
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
auto_actions :all
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Will have all of the above actions.
\end_layout
\begin_layout Standard
You can customize this either by listing the actions you want:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
auto_actions :new, :create, :show
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Or by listing the actions you
\begin_inset Flex Emph
status collapsed
\begin_layout Plain Layout
don’t
\end_layout
\end_inset
want:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
auto_actions :all, :except => [ :index, :destroy ]
\end_layout
\end_inset
\end_layout
\begin_layout Standard
The
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:except
\end_layout
\end_inset
option can be set to either a single symbol or an array
\end_layout
\begin_layout Standard
There are two more conveniences:
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:read_only
\end_layout
\end_inset
and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:write_only
\end_layout
\end_inset
.
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:read_only
\end_layout
\end_inset
is a shorthand for
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:index
\end_layout
\end_inset
and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:show
\end_layout
\end_inset
, and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:write_only
\end_layout
\end_inset
is a shorthand for
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:create
\end_layout
\end_inset
,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:update
\end_layout
\end_inset
and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:destroy
\end_layout
\end_inset
.
\end_layout
\begin_layout Standard
Either of these shorthands must be the first argument to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
auto_actions
\end_layout
\end_inset
, after which you can still list other actions and the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:except
\end_layout
\end_inset
option:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
auto_actions :write_only, :show
\end_layout
\end_inset
\end_layout
\begin_layout Section
Owner actions
\end_layout
\begin_layout Standard
Hobo’s model controller can also provide three special actions that take
into account the relationships between your records.
Specifically, these are the “owner” versions of new, index and create.
To understand how these compare to the usual actions, consider a recipe
model which
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
belongs_to :author, :class_name => "User"
\end_layout
\end_inset
.
The three special actions are:
\end_layout
\begin_layout Itemize
An index page that only lists the recipes by a specific author
\end_layout
\begin_layout Itemize
A “New Recipe” page specific to that user (i.e.
to create a new recipe by that author)
\end_layout
\begin_layout Itemize
A create action which is specific to that “New Recipe” page
\end_layout
\begin_layout Standard
These are all part of the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
RecipesController
\end_layout
\end_inset
and can be added with the a
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
uto_actions_for
\end_layout
\end_inset
declaration, like this:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
auto_actions_for :author, [ :index, :new, :create ]
\end_layout
\end_inset
\end_layout
\begin_layout Standard
If you only want one, you can omit the brackets:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
auto_actions_for :author, :index
\end_layout
\end_inset
\end_layout
\begin_layout Subsubsection*
Action names and routes
\end_layout
\begin_layout Standard
The action names and routes for these actions are as follows:
\end_layout
\begin_layout Itemize
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
index_for_author
\end_layout
\end_inset
is routed as
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
/users/:author_id/products
\end_layout
\end_inset
for GET requests
\end_layout
\begin_layout Itemize
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
new_for_author
\end_layout
\end_inset
is routed as
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
/users/:author_id/products/new
\end_layout
\end_inset
for GET requests
\end_layout
\begin_layout Itemize
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
create_for_author
\end_layout
\end_inset
is routed as
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
/users/:author_id/products
\end_layout
\end_inset
for POST requests
\end_layout
\begin_layout Standard
It’s common for the association name and the class name of the target to
be the same (e.g., in an association like
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
belongs_to :category
\end_layout
\end_inset
).
We’ve deliberately chosen an example where they are different (“author”
and “user”) in order to show where the two names are used.
The association name (“author”) is used everywhere except in the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
/users
\end_layout
\end_inset
at the beginning of the route.
\end_layout
\begin_layout Subsubsection*
Instance Variables
\end_layout
\begin_layout Standard
As well as setting the default DRYML context, the default actions all make
the record, or collection of records, available to the view in an instance
variable that follows Rails conventions.
E.g.
for a ‘product’ model, the product will be available as
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
@product
\end_layout
\end_inset
and the collection of products on an index page will be available as
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
@products
\end_layout
\end_inset
\end_layout
\begin_layout Subsubsection*
Owner actions
\end_layout
\begin_layout Standard
For owner actions, the owner record is made available as
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
@<association-name>
\end_layout
\end_inset
.
For example, .
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
@author
\end_layout
\end_inset
in our above example.
\end_layout
\begin_layout Subsubsection*
Automatic Routes
\end_layout
\begin_layout Standard
Hobo’s model router will automatically create standard RESTful routes for
each of your models.
The router inspects your controllers: any action that is not defined will
not be routed.
\end_layout
\begin_layout Standard
The default routes created by Hobo are located in the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
config/hobo_routes.rb
\end_layout
\end_inset
file.
You can override these by placing entries in the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
config/routes.rb
\end_layout
\end_inset
file.
\end_layout
\begin_layout Section
Adding extra actions
\end_layout
\begin_layout Standard
It’s common to want actions beyond the basic REST defaults.
In Rails a controller action is simply a public method.
That doesn’t change in Hobo.
You can define public methods and add routes for them just as you would
in a regular Rails app.
However, you probably want your new actions to be routed automatically,
and even implemented automatically, just like the basic actions.
For this to happen you have to tell Hobo about them as explained in this
section.
\end_layout
\begin_layout Subsubsection*
Show actions
\end_layout
\begin_layout Standard
Suppose we want a normal view and a “detailed” view of our advert.
In REST terms we want a new ‘show’ action called ‘detail’.
We can add this like this:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
class AdvertsController < ActiveRecord::Base
\end_layout
\begin_layout Code
hobo_model_controller
\end_layout
\begin_layout Code
auto_actions :all
\end_layout
\begin_layout Code
show_action :detail
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
This action will be routed to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
/adverts/:id/detail
\end_layout
\end_inset
.
\end_layout
\begin_layout Standard
Hobo will provide a default implementation.
You can override this simply by defining the method yourself:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
show_action :detail
\end_layout
\begin_layout Code
def detail
\end_layout
\begin_layout Code
...
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Or, as a shorthand for the same, give a block to show_action:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
show_action :detail do
\end_layout
\begin_layout Code
...
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Subsubsection*
Index actions
\end_layout
\begin_layout Standard
In the same way, we might want an alternative listing (index) of our adverts.
Perhaps one that gives a tabular view of the adverts:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
class AdvertsController < ActiveRecord::Base
\end_layout
\begin_layout Code
hobo_model_controller
\end_layout
\begin_layout Code
auto_actions :all
\end_layout
\begin_layout Code
index_action :table
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
This gets routed to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
/adverts/table
\end_layout
\end_inset
.
As with
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
show_action
\end_layout
\end_inset
, if you want your own implementation, you can either define the method
as normal, or pass a block to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
index_action
\end_layout
\end_inset
.
\end_layout
\begin_layout Section
Changing action behavior
\end_layout
\begin_layout Standard
Sometimes the implementations Hobo provide aren’t what you want.
They might be close, or they might be completely out.
Not a problem - you can change things as needed.
\end_layout
\begin_layout Subsubsection*
A cautionary note concerning controller methods
\end_layout
\begin_layout Standard
Always start by asking: should this go in the model? It’s a very, very,
very common mistake to put code in the controller that belongs in the model.
Want to send an email in the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
create
\end_layout
\end_inset
action?
\end_layout
\begin_layout Standard
Don’t! Send it from an
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
after_create
\end_layout
\end_inset
callback in the model.
Want to check something about the current user before allowing a
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
destroy
\end_layout
\end_inset
to proceed? Use Hobo’s
\begin_inset CommandInset href
LatexCommand href
name "Permission System"
target "http://cookbook.hobocentral.net/manual/permissions"
\end_inset
.
\end_layout
\begin_layout Standard
Typically, valid reasons to add custom controller code are things like:
\end_layout
\begin_layout Itemize
Provide a custom flash message
\end_layout
\begin_layout Itemize
Change the redirect after a create / update / destroy
\end_layout
\begin_layout Itemize
Extract parameters from
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
params
\end_layout
\end_inset
and pass them to the model (e.g.
for searching / filtering)
\end_layout
\begin_layout Itemize
Provide special responses for different formats or requested mime-types
\end_layout
\begin_layout Standard
A good test is to ask: is this related to http? No? Then it probably shouldn’t
be in the controller.
I tend to think of controllers as a way to publish objects via http, so
they shouldn’t really be dealing with anything else.
\end_layout
\begin_layout Section
Writing an action
\begin_inset Newline newline
\end_inset
from scratch
\end_layout
\begin_layout Standard
The simplest way to customize an action is to write it yourself.
Say your advert has a boolean field
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
published
\end_layout
\end_inset
and you only want published adverts to appear on the index page.
Using one of Hobo’s automatic scopes, you could write:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
class AdvertsController < ActiveRecord::Base
\end_layout
\begin_layout Code
hobo_model_controller
\end_layout
\begin_layout Code
auto_actions :all
\end_layout
\begin_layout Code
def index
\end_layout
\begin_layout Code
@adverts = Advert.published.all
\end_layout
\begin_layout Code
end
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
In other words you don’t need to do anything different than you would in
a normal Rails action.
Hobo will look for either
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
@advert
\end_layout
\end_inset
(for actions which expect an ID) or
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
@adverts
\end_layout
\end_inset
(for index actions) as the initial context for a DRYML page.
\end_layout
\begin_layout Standard
\begin_inset Box Shaded
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Description
Note: In the above example, we’ve asked for the default
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
index
\end_layout
\end_inset
action and then overwrote it.
It might have been neater to say ”
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
auto_actions :all, :except => :index
\end_layout
\end_inset
” but it really doesn’t matter.
\end_layout
\end_inset
\end_layout
\begin_layout Subsubsection*
Customizing Hobo’s implementation
\end_layout
\begin_layout Standard
Often you
\begin_inset Flex Emph
status collapsed
\begin_layout Plain Layout
do
\end_layout
\end_inset
want the automatic action, but you want to customize it in some way.
The way you do this varies slightly for the different kinds of actions,
but they all follow the same pattern.
We’ll start with
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
show
\end_layout
\end_inset
as an example.
\end_layout
\begin_layout Standard
The default
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
show
\end_layout
\end_inset
provided by Hobo is simply:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
def show
\end_layout
\begin_layout Code
hobo_show
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
All the magic (and in the case of
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
show
\end_layout
\end_inset
there really isn’t much) takes place in
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_show
\end_layout
\end_inset
.
So immediately we can see that it’s easy to add code before or after the
default behavior:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
def show
\end_layout
\begin_layout Code
@foo = "bar"
\end_layout
\begin_layout Code
hobo_show
\end_layout
\begin_layout Code
logger.info "Done show!"
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Note: assigning to instance variables to make data available to the views
work exactly as it normally would in Rails.
\end_layout
\begin_layout Standard
There is a similar
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_*
\end_layout
\end_inset
method for each of the basic actions:
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_new
\end_layout
\end_inset
,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_index
\end_layout
\end_inset
, etc.
\end_layout
\begin_layout Standard
Switching to the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
update
\end_layout
\end_inset
action, you might think you can do:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
def update
\end_layout
\begin_layout Code
hobo_update
\end_layout
\begin_layout Code
redirect_to my_special_place # DON'T DO THIS!
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
That will give you an error: actions can only respond by doing a
\begin_inset Flex Emph
status collapsed
\begin_layout Plain Layout
single
\end_layout
\end_inset
redirect or render, and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_update
\end_layout
\end_inset
has already done a redirect.
Read on for the simple solution…
\end_layout
\begin_layout Subsubsection*
The block
\end_layout
\begin_layout Standard
The correct place to perform a redirect is in a block passed to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_update
\end_layout
\end_inset
.
All the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_*
\end_layout
\end_inset
actions take a block and yield to the block just before their response.
If your block performed a response, Hobo will leave it at that.
So:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
def update
\end_layout
\begin_layout Code
hobo_update do
\end_layout
\begin_layout Code
redirect_to my_special_place
\end_layout
\begin_layout Code
# better but still problematic
\end_layout
\begin_layout Code
end
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
The problem this time is that we almost certainly don’t want to do that
redirect if there were validation errors during the update.
As with the typical Rails pattern, validation errors are handled by re-renderin
g the form (along with the error messages).
Hobo provides a method
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
valid?
\end_layout
\end_inset
for these situations:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
def update
\end_layout
\begin_layout Code
hobo_update do
\end_layout
\begin_layout Code
redirect_to my_special_place if valid?
\end_layout
\begin_layout Code
end
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
If the update was valid, the above redirect will happen.
If it wasn’t, the block won’t respond so Hobo’s response will kick in and
re-render the form.
Perfect!
\end_layout
\begin_layout Standard
If you want access to the object either in the block or after the call to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_update
\end_layout
\end_inset
, it’s available either as
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
this
\end_layout
\end_inset
or in the conventional Rails instance variable, in this case
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
@advert
\end_layout
\end_inset
.
\end_layout
\begin_layout Subsubsection*
Handling different formats
\end_layout
\begin_layout Standard
By default, the response block is only called if an HTML response is required.
If you want to handle other response types, declare a block with a single
argument.
The “format” object from Rails’
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
respond_to
\end_layout
\end_inset
will be passed.
The typical usage would be:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
def update
\end_layout
\begin_layout Code
hobo_update do |format|
\end_layout
\begin_layout Code
format.html { ...
}
\end_layout
\begin_layout Code
format.js { ...
}
\end_layout
\begin_layout Code
end
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Subsubsection*
Passing options
\end_layout
\begin_layout Standard
Here’s another example of tweaking one of the automatic actions.
The
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_*
\end_layout
\end_inset
methods can all be passed a range of options.
Here’s a simple example: changing the page size on an index page:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
def index
\end_layout
\begin_layout Code
hobo_index :per_page => 10
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
That’s pretty much all there is to customizing Hobo’s automatic actions:
define the action as a public method in which you call the appropriate
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_*
\end_layout
\end_inset
method, passing it parameters and/or a block.
\end_layout
\begin_layout Standard
The remainder of this guide will cover the parameters available to each
of the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_*
\end_layout
\end_inset
methods.
Note that you can also pass these options directly to the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
index_action
\end_layout
\end_inset
and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
show_action
\end_layout
\end_inset
declarations, e.g.:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
index_action :table, :per_page => 10
\end_layout
\end_inset
\end_layout
\begin_layout Section
The default actions
\end_layout
\begin_layout Standard
In this section we’ll go through each of the action implementations that
Hobo provides.
\end_layout
\begin_layout Subsubsection*
Hobo_index
\end_layout
\begin_layout Standard
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_index
\end_layout
\end_inset
takes a “finder” as an optional first argument, and then options.
A finder is any object that supports the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
find
\end_layout
\end_inset
and / or
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
paginate
\end_layout
\end_inset
methods, such as an ActiveRecord model class, a
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
has_many
\end_layout
\end_inset
association, or a scope.
\end_layout
\begin_layout Subsubsection*
Find options
\end_layout
\begin_layout Standard
Any of the standard ActiveRecord find options you pass are forwarded to
the find method.
This is particularly useful with the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:include
\end_layout
\end_inset
option to avoid the dreaded N+1 query problem.
\end_layout
\begin_layout Subsubsection*
Pagination
\end_layout
\begin_layout Standard
Turn pagination on or off by passing true/false to the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:paginate
\end_layout
\end_inset
option.
If not specified Hobo will guess based on the value of
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
request.format
\end_layout
\end_inset
.
\end_layout
\begin_layout Standard
It’s normally on, but won’t be for things like XML and CSV.
When pagination is on, any other options to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_index
\end_layout
\end_inset
are forwarded to the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
paginate
\end_layout
\end_inset
method from will-paginate, so you can pass things like
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:page
\end_layout
\end_inset
and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:per_page
\end_layout
\end_inset
.
If you don’t specify
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:page
\end_layout
\end_inset
it defaults to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
params[:page]
\end_layout
\end_inset
or if that’s not given, the first page.
\end_layout
\begin_layout Subsubsection*
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_show
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Options to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_show
\end_layout
\end_inset
are forwarded to the method
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
find_instance
\end_layout
\end_inset
which does:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
model.user_find(current_user, params[:id], options)
\end_layout
\end_inset
\end_layout
\begin_layout Standard
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
user_find
\end_layout
\end_inset
is a method added to your model by Hobo which combines a normal find with
a check for view permission.
\end_layout
\begin_layout Standard
As with
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_index
\end_layout
\end_inset
, a typical use would be to pass
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:include
\end_layout
\end_inset
to do eager loading.
\end_layout
\begin_layout Subsubsection*
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_new
\end_layout
\end_inset
\end_layout
\begin_layout Standard
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_new
\end_layout
\end_inset
will either instantiate the model for you using the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
user_new
\end_layout
\end_inset
method from Hobo’s permission system, or will use the first argument (if
you provide one) as the new record.
\end_layout
\begin_layout Subsubsection*
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_create
\end_layout
\end_inset
\end_layout
\begin_layout Standard
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_create
\end_layout
\end_inset
will instantiate the model (using
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
user_new
\end_layout
\end_inset
), or take the first argument if you provide one.
\end_layout
\begin_layout Standard
The attributes hash for this new record are found either from the option
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:attributes
\end_layout
\end_inset
if you passed one, or from the conventional parameter that matches the
model name (e.g.
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
params[:advert]
\end_layout
\end_inset
).
\end_layout
\begin_layout Standard
The update to the new record with these attributes is performed using the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
user_update_attributes
\end_layout
\end_inset
method, in order to respect the model’s permissions.
\end_layout
\begin_layout Standard
The response (assuming you didn’t respond in the block) will handle:
\end_layout
\begin_layout Itemize
redirection if the create was valid (see below for details)
\end_layout
\begin_layout Itemize
re-rendering the form if not (or sending textual validation errors back
to an AJAX caller)
\end_layout
\begin_layout Itemize
performing Hobo’s part updates as required for AJAX requests
\end_layout
\begin_layout Subsubsection*
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_update
\end_layout
\end_inset
\end_layout
\begin_layout Standard
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_update
\end_layout
\end_inset
has the same behavior as
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_create
\end_layout
\end_inset
except that the record is found rather than created.
You can pass the record as the first argument if you want to find it yourself.
The response is also essentially the same as
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_create
\end_layout
\end_inset
, with some extra smarts to support the in-place-editor from Script.aculo.us.
\end_layout
\begin_layout Subsubsection*
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_destroy
\end_layout
\end_inset
\end_layout
\begin_layout Standard
The record to destroy is found using the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
find_instance
\end_layout
\end_inset
method, unless you provide it as the first argument.
\end_layout
\begin_layout Standard
The actual destroy is performed with:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
this.user_destroy(current_user)
\end_layout
\end_inset
\end_layout
\begin_layout Standard
…which performs a permission check first.
\end_layout
\begin_layout Standard
The response is either a redirect or an AJAX part update as appropriate.
\end_layout
\begin_layout Section
Owner actions
\end_layout
\begin_layout Standard
For the “owner” versions of the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
index
\end_layout
\end_inset
,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
new
\end_layout
\end_inset
and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
create
\end_layout
\end_inset
actions, Hobo provides:
\end_layout
\begin_layout Itemize
hobo_index_for
\end_layout
\begin_layout Itemize
hobo_new_for
\end_layout
\begin_layout Itemize
hobo_create_for
\end_layout
\begin_layout Standard
These are pretty much the same as the regular
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_index
\end_layout
\end_inset
,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_new
\end_layout
\end_inset
and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_create
\end_layout
\end_inset
except they take an additional first argument – the name of the association.
For example, the default implementation of, say,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
index_for_author
\end_layout
\end_inset
would be:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
def index_for_author
\end_layout
\begin_layout Code
hobo_index_for :author
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Subsubsection*
Flash messages
\end_layout
\begin_layout Standard
The
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_create
\end_layout
\end_inset
,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_update
\end_layout
\end_inset
and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_destroy
\end_layout
\end_inset
actions all set reasonable flash messages in
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
flash[:notice]
\end_layout
\end_inset
.
They do this before your block is called so you can simply overwrite this
message with your own if need be.
\end_layout
\begin_layout Standard
Automatic redirection The
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_create
\end_layout
\end_inset
,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_create_for
\end_layout
\end_inset
,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_update
\end_layout
\end_inset
and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_destroy
\end_layout
\end_inset
actions all perform a redirect on success.
\end_layout
\begin_layout Subsubsection*
Block Response
\end_layout
\begin_layout Standard
If you supply a block to the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_*
\end_layout
\end_inset
action, no redirection is done so that it may be performed by the block:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
def update
\end_layout
\begin_layout Code
hobo_update do
\end_layout
\begin_layout Code
redirect_to my_special_place if valid?
\end_layout
\begin_layout Code
end
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Subsubsection*
The
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:redirect
\end_layout
\end_inset
parameter
\end_layout
\begin_layout Standard
If you supply a block to the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_*
\end_layout
\end_inset
action, you must redirect or render all potential formats.
But what if you want to supply a redirect for HTML requests, but let Hobo
handle AJAX requests? In this case you can supply the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:redirect option
\end_layout
\end_inset
to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_*
\end_layout
\end_inset
:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
def update
\end_layout
\begin_layout Code
hobo_update :redirect => my_special_place
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:redirect
\end_layout
\end_inset
is only used for valid HTML requests.
\end_layout
\begin_layout Standard
The
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
redirect:
\end_layout
\end_inset
option may be one of:
\end_layout
\begin_layout Itemize
Symbol: redirects to that action using the current controller and model.
(Must be a show action).
\end_layout
\begin_layout Itemize
Hash or String:
\begin_inset CommandInset href
LatexCommand href
name "redirect\\to"
target "http://api.rubyonrails.org/classes/ActionController/Base.html"
\end_inset
is used.
\end_layout
\begin_layout Itemize
Array:
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
object_url
\end_layout
\end_inset
is used.
\end_layout
\begin_layout Subsubsection*
Automatic redirects
\end_layout
\begin_layout Standard
If neither a response block nor
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:redirect
\end_layout
\end_inset
are passed to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_*
\end_layout
\end_inset
, the destination of this redirect is determined by calling the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
destination_after_submit
\end_layout
\end_inset
method.
Here’s how it works:
\end_layout
\begin_layout Itemize
If the parameter ”
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
after_submit
\end_layout
\end_inset
” is present, go to that URL (See the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
<after-submit>
\end_layout
\end_inset
tag in Rapid for an easy way to provide this parameter), or
\end_layout
\begin_layout Itemize
Go to the record’s
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
show
\end_layout
\end_inset
page if there is one, or
\end_layout
\begin_layout Itemize
Go to the show page of the object’s
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
owner
\end_layout
\end_inset
if there is one (For example, this might take you to the blog post after
editing a comment), or
\end_layout
\begin_layout Itemize
Go to the index page for this model if there is one, or
\end_layout
\begin_layout Itemize
Give up trying to be clever and go to the home-page (the root URL, or override
by implementing
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
home_page
\end_layout
\end_inset
in ApplicationController)
\end_layout
\begin_layout Section
Autocompleters
\end_layout
\begin_layout Standard
Hobo makes it easy to build auto-completing text fields in your user interface;
the Rapid tag library provides support for them in the view layer, and
the controller provides an easy way to add the action that looks up the
completions.
The simplest form for creating an auto-completing field is just a single
declaration:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
class UsersController < ApplicationController
\end_layout
\begin_layout Code
autocomplete
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Because Hobo allows you to specify which field of a model is the name (using
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:name => true
\end_layout
\end_inset
in the model’s field declaration block), you don’t need to tell
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
autocomplete
\end_layout
\end_inset
which field to complete on if it is autocompleting the “name” field.
To create an autocompleter for a different field, pass the field as a symbol:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
autocomplete :email_address
\end_layout
\end_inset
\end_layout
\begin_layout Standard
The
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
autocomplete
\end_layout
\end_inset
declaration will create an action named according to the field, e.g.,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
complete_email_address
\end_layout
\end_inset
routed as, in this case,
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
/users/complete_email_address
\end_layout
\end_inset
for GET requests.
\end_layout
\begin_layout Subsubsection*
Options
\end_layout
\begin_layout Standard
The autocomplete behavior can be customized with the following options:
\end_layout
\begin_layout Itemize
:field – specify a field to complete on.
Defaults to the name (first argument) of the autocompleter.
\end_layout
\begin_layout Itemize
:limit – maximum number of completions.
Defaults to 10.
\end_layout
\begin_layout Itemize
:param – name of the parameter in which to expect the user’s input.
Defaults to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
:query
\end_layout
\end_inset
\end_layout
\begin_layout Itemize
:query_scope – a named scope used to do the database query.
Change this to control things such as handling of multiple words, case
sensitivity, etc.
For our example this would be
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
email_address_contains
\end_layout
\end_inset
.
Note that this is one of Hobo’s automatic scopes.
\end_layout
\begin_layout Section
Further Customization
\end_layout
\begin_layout Standard
The autocomplete action follows the same pattern for Customization as the
regular actions.
That is, the implementation given to you is a simple call to the underlying
method that does the actual work, and you can call this underlying method
directly.
To illustrate, say, on a
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
UsersController
\end_layout
\end_inset
in which you declare
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
autocomplete :email_address
\end_layout
\end_inset
, the generated method looks like:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
def complete_email_address
\end_layout
\begin_layout Code
hobo_completions :email_address, User
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
To gain extra control, you can call
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_completions
\end_layout
\end_inset
yourself by passing a block to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
autocomplete
\end_layout
\end_inset
:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
autocomplete :email_address do
\end_layout
\begin_layout Code
hobo_completions
\end_layout
\begin_layout Code
...
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
The parameters to
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
hobo_completions
\end_layout
\end_inset
are:
\end_layout
\begin_layout Itemize
Name of the attribute
\end_layout
\begin_layout Itemize
A finder, i.e.
a model class, association, or a scope.
\end_layout
\begin_layout Itemize
Options (the same as described above)
\end_layout
\begin_layout Section
Drag and drop reordering
\end_layout
\begin_layout Standard
The controller has the server-side support for drag-and-drop reordering
of models that declare
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
acts_as_list
\end_layout
\end_inset
.
\end_layout
\begin_layout Standard
Say, for example, your
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
Task
\end_layout
\end_inset
model uses
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
acts_as_list
\end_layout
\end_inset
, then Hobo will add a
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
reorder
\end_layout
\end_inset
action routed as
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
/tasks/reorder
\end_layout
\end_inset
that looks like:
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
def reorder
\end_layout
\begin_layout Code
hobo_reorder
\end_layout
\begin_layout Code
end
\end_layout
\end_inset
\end_layout
\begin_layout Standard
This action expects an array of IDs in
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
params[:task_ordering]
\end_layout
\end_inset
, and will reorder the records in the order that the IDs are given.
\end_layout
\begin_layout Standard
The action can be removed in the normal ways (e.g., blacklisting):
\end_layout
\begin_layout Standard
\begin_inset Box Shadowbox
position "t"
hor_pos "c"
has_inner_box 1
inner_pos "t"
use_parbox 0
use_makebox 0
width "100col%"
special "none"
height "1in"
height_special "totalheight"
status open
\begin_layout Code
auto_actions :all, :except => :reorder
\end_layout
\end_inset
\end_layout
\begin_layout Standard
The action will raise a
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
PermissionDeniedError
\end_layout
\end_inset
if the current user does not have permission to change the ordering.
\end_layout
\begin_layout Subsection*
Permission and “not-found” errors
\end_layout
\begin_layout Standard
Any permission errors that happen are handled by the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
permission_denied
\end_layout
\end_inset
controller method, which renders the DRYML tag
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
<permission-denied-page>
\end_layout
\end_inset
or just a text message if that doesn’t exist.
\end_layout
\begin_layout Standard
Not-found errors are handled in a similar way by the
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
not_found
\end_layout
\end_inset
method, which tries to render
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
<not-found-page>
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Both
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
permission_denied
\end_layout
\end_inset
and
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
not_found
\end_layout
\end_inset
can be overridden either in an individual controller or site-wide in
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
ApplicationController
\end_layout
\end_inset
.
\end_layout
\begin_layout Subsection*
Lifecycles
\end_layout
\begin_layout Standard
Hobo’s model controller has extensive support for lifecycles.
This is described in the following chapter.
\end_layout
\begin_layout Standard
 
\end_layout
\end_body
\end_document
Jump to Line
Something went wrong with that request. Please try again.