Provided by: libjifty-perl_1.10518+dfsg-3ubuntu1_all bug

NAME

       Jifty::Manual::Actions - Doing Stuff With Jifty

DESCRIPTION

       "Jifty::Action" abstracts around the idea of declaring named ("parameters") at compile
       time.  At runtime, the action collects user input as ("arguments"), does something with
       them, and returns some result to the user.  If this sounds incredibly general, that's
       because it is -- actions do nearly everything in Jifty.

       "Jifty::Action" will also generate HTML for you from its parameters -- no more manually
       writing "<input>" tags and extracting GET and POST arguments by hand and dispatching them
       where they belong -- "Jifty::Action" does it all for you.

WRITING ACTIONS

       Jifty provides some actions for you out of the box -- see Jifty::Manual::ObjectModel and
       Jifty::Action::Record for autogenerated actions, as well as Jifty::Action::Redirect, but
       any non-trivial application will want to define actions of its own. This is how you do it.

       Every action is a subclass of Jifty::Action, as well as typically AppName::Action. Actions
       usually live in the AppName::Action:: namespace; while that's just a convention, it will
       make your life easier if you follow it.

       This, the simplest possible action, is:

           use warnings;
           use strict;

           package MyApp::Action::DoNothing;
           use base qw/MyApp::Action Jifty::Action/;

           1;

       (Instead of copying-and-pasting that, or typing it in, though, you could just run:

           jifty action --name DoNothing

       in your application's directory, and Jifty would create a skeleton for you. )

       However, if you want to actually do something with your actions, you need to define two
       things: their parameters, and a "take_action" method.

   parameters
       Every "Jifty::Action" subclass should define a "schema", which contains some "param"
       declarations that describe what arguments it takes.  Supposing we were writing an action
       to post a blog article, we might start out with parameters like thus:

           use Jifty::Param::Schema;
           use Jifty::Action schema {

           param 'title';
           param 'category';
           param 'body';

           };

       However, we've only scratched the surface of the power the "param" API offers.  Parameters
       can have types, labels, validators, canonicalizers, and even more. To start with, let's
       add some types and labels:

           use Jifty::Param::Schema;
           use Jifty::Action schema {

           param title =>
               label is 'Title',
               max_length is 50,
               is mandatory;

           param category =>
               label is 'Category',
               max_length is 30;

           param body =>
               label is 'Entry',
               render as 'Textarea';

           };

       Now, we can ask the action to render form fields, and it will know how to display them.
       But, we can do even better. Let's improve the look of that "category" field, by making it
       a combobox (a combination dropdown/text field), with some default values available:

           # ...
           param category =>
               label is 'Category',
               render as 'Combobox',
               available are qw( Personal Work Block );
           # ...

       But a static list is lame. What we really want is a "Category" model, and to keep track of
       all the categories users have entered:

           # ...
           param categories =>
               label is 'Category',
               render as 'Select',
               available are defer {
                   my $categories = MyBlog::Model::CategoryCollection->new;
                   $categories->unlimit;
                   [{
                       display_from => 'name',
                       value_from   => 'name',
                       collection   => $categories,
                   }];
               }
           ...

       Now, Jifty will populate the combobox with the result of calling "name" on each element in
       $categories. Alternatively, if you set "value_from => 'id'", Jifty would automatically
       return the "id" of the category, for easy database reference. We don't do this with the
       combobox, however, since a combobox displays the selected value in its text field.

       See Jifty::Action and Jifty::Web::Form::Field for more fields you can set in the "param"
       declaration, and see Jifty::Param::Schema for more about the syntax.

   validation
       "Jifty::Action" can automatically validate arguments for you, as appropriate. If an
       argument has "valid_values", then "Jifty::Action" will automatically verify if the given
       value matches one of them. However, you can also write your own validators. Just write a
       "sub validate_<parameter>", and it will be called as appropriate:

           use Regexp::Common 'profanity_us';

           sub validate_body {
              my $self = shift;
              my $body = shift;

              if ( $body =~ /$RE{profanity}/i) {
                  return $self->validation_error(
                      body => 'Would you speak like that in front of your mother? *cough*'
                  );
              }
              return $self->validation_ok('body');
           }

       Your "validate_<parameter>" method will be called with the value of "<parameter>" followed
       by two hash references. The first is a hash reference of the full set of arguments passed
       along with "<parameter>" to permit more advanced validation. For example you could forbid
       profanity only if the content is "rated" for all ages. The final parameter is another hash
       reference of extra metadata. The "for" key will be set to "create" or "update" to give you
       still more control.

       You can also do validation in the model -- see Jifty::Action::Record.

   canonicalization
       If, instead of failing, you want to automatically modify invalid content to be valid, you
       want a canonicalizer, not a validator.

           use Regexp::Common 'profanity_us';

           sub canonicalize_body {
              my $self = shift;
              my $body = shift;
              $body =~ s/$RE{profanity}/**expletives**/gi;
              return $body;
           }

       Note that the parameters (value, all parameters, metadata) are the same as in
       "validation".

       A canonicalizer can also change other parts of the action.  This lets you update the
       display dynamically in an AJAX-enabled browser based on what the user has entered.  For
       example, we can let a user use magic syntax to provide tags for their blog post by
       surrounding the tags with square brackets.  You can also let the user know you're doing
       something magical by using "canonicalization_note" which will display a message to the
       user.

           use Jifty::Param::Schema;
           use Jifty::Action schema {
               param title =>
                   label is 'Title',
                   hints is "You can provide tags like this [tag1 tag2]",
                   ajax canonicalizes;

               param tags =>
                   label is 'Tags';
           };

           sub canonicalize_title {
               my $self = shift;
               my $value = shift;

               if ($value =~ s/\[(.*?)\]//) {
                   # this clobbers, may want to merge
                   $self->argument_value( tags => $1 );
                   $self->canonicalization_note(
                       title => 'Removed tags from your title'
                   );
               }

               return $value;
           }

       If you set "ajax validates" or "ajax canonicalizes" for an argument, then Jifty will
       automatically validate or canonicalize it in an AJAX-enabled browser when the user stops
       typing and puts the focus out of the corresponding form field.

   take_action
       Once an action has arguments, it needs to do something with them. An action does so in its
       "take_action" sub, which will be called when an action is submitted, and only if its
       arguments validate.

       Inside "sub take_action", subclasses can access their arguments via
       "$self->argument_value('foo')". If you need to check whether you've been passed an
       argument or not (as opposed to being passed a true argument or not), use
       "$self->has_argument('foo')".

       Once an action has done its task, it needs to inform the caller whether or not it has
       succeeded, possibly with some status message. To this end, every "Jifty::Action" has a
       "Jifty::Result" associated with. "Jifty::Result" carries both a failure/sucess code, and a
       textual message describing the result of running the action.

       Thus, if your action failed for some reason, you would, in "take_action", write code like:

           $self->result->error('Could not write blog post');
           return;

       If, however, the action completed successfully, you might write:

           $self->result->message('Posted to your blog');

       Actions will default to successful with an empty message if you don't do anything with the
       result object. Additionally, if you need to return more semantic information than a simple
       message, you can set arbitrary content on the result, using $self->result->content, e.g:

           $self->result->content( id => $new_post->id);

       This information can be then used elsewhere to, for example, automatically redirect you to
       a view page for that new blog post. The view page template may have the following piece of
       code in it:

           <%args>
           $id => undef
           </%args>
           <%init>
           my $result = Jifty->web->response->result('post_blog');
           $id = $result->content('id') if $result and !defined $id;
           # load the record by $id and other stuff go here...
          </%init>

       where 'post_blog' is the moniker for your post page action object.  In fact, that's
       exactly how actions "return" values to other components in your application.

       Multiple action "return values" are possible and arbitrary data structures can be passed
       too:

           $self->result->content( keys   => $keys );
           $self->result->content( result => $collection);

       It should also be mentioned that the response object is "per request". That is, it usually
       can't live up to another user request. Therefore, when paging mechanism is applied to your
       view page, for example, you have to either pass some data to the link constructor or
       explicitly tell Jifty to preserve states for you.

       See "monikers", the Jifty Pony site's source, and Jifty::Request::Mapper for some more
       information.

USING ACTIONS

       At their simplest, you can create and run actions yourself, e.g.:

           Jifty->web->new_action(
               class     => 'PostBlogEntry',
               arguments => {
                   title    => 'A boring blog entry',
                   category => 'Jifty',
                   body     => 'This blog entry is lame.'
               }
           )->run;

       Note that "Jifty->web->new_action", and all similar methods (e.g.
       Jifty::Request::add_action, Jifty::Web::Form::add_action), will automatically qualify the
       "class" with either "Jifty::Action::" or "AppName::Action::" as necessary (I've told you
       putting actions in AppName::Action:: would make your life easier!)

       In practice, you'll rarely provide actions with arguments yourself. Instead, you'll create
       an action with no or partial arguments, often in the dispatcher, or a Mason component's
       "<%init%>" block (See "constructor arguments" for details about passing arguments to
       actions on creation).

           my $create = Jifty->web->new_action(
               class   => 'PostBlogEntry',
               moniker => 'post_blog'
           );

       Having created the action, you will, in one of your Mason components, output a form where
       the user can fill in the action's arguments:

           <% Jifty->web->form->start %>
           <div class="post-metadata">
             <% $create->form_field('title') %>
             <% $create->form_field('category') %>
           </div>
             <% $create->form_field('body') %>
           <% Jifty->web->form->submit(label => "Post") %>
           %# or <% Jifty->web->link(label => "Post", submit => $create) %>
           %# or <% $action->button(label => "Post"); %>
           <% Jifty->web->form->end %>

       "form_field" will render the field, along with the "label" as an HTML "<input>" tag that
       Jifty knows how to interpret to feed back to your action as an argument when the form is
       submitted. If you need to change the appearance of the field, Jifty outputs classes on the
       fields, as well as providing some semantic "<div>"s you can style using CSS. (See
       Jifty::Manual::UsingCSSandJS for some more details.)

       See "submit" in Jifty::Web::Form, "link" in Jifty::Web and "button" in Jifty::Action for
       details on the different ways to generate a submit button.

       Additionally, instead of "form_field", you can use "hidden" to generate a "hidden" input,
       which will not be viewable or editable in a web browser. (Note that a knowledgeable user
       can still submit a form with a different value for that hidden input; If this concerns
       you, make sure you have appropriate ACLs in place. If it still worries you, you probably
       want a continuation here.)

   monikers
       You probably noticed the "moniker => 'post_blog'". Every action you create in Jifty has an
       associated moniker. A "moniker" is simply a unique identifier for the action (unique per
       request, which in practice typically means per HTML page). Since actions are constantly
       being serialized (over HTTP, or Javascript AJAX calls, and so on), and unpacked, we need a
       way refer to specific actions other than just object identity, e.g. to extract its
       arguments or results in the dispatcher or a template. Monikers give us that. Given a
       moniker, you can pull information about the associated action out of a request or
       response.

       If a moniker is unspecified, it will be autogenerated.

       (XXX TODO Note about action registration here)

   Argument Folding
       If you write out more than one "form_field" for a given argument in the same form, and
       more than one is filled in, Jifty will "fold" the arguments into an array before filling
       them in to the action. This provides a way to do, e.g. a "BulkEdit" action that applies
       some set of changes to many records at once.

       (XXX TODO Note about "constructor" parameters)

ACTIONS AS WEB SERVICES

       Your actions are also automatically published as web services.  Clients can POST requests,
       usually using the YAML or JSON request format.  See "bin/service" for a trivial generic
       webservice client.

       (XXX TODO More about webservices)

SEE ALSO

       Jifty::Action, Jifty::Manual::Tutorial