[Jifty-commit] r1384 - in jifty: .

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Wed Jun 28 12:12:39 EDT 2006

Author: nelhage
Date: Wed Jun 28 12:12:38 2006
New Revision: 1384

   jifty/   (props changed)

 r13231 at phanatique:  nelhage | 2006-06-28 18:04:43 +0200
 J::Action documentation++

Added: jifty/trunk/lib/Jifty/Manual/Actions.pod
--- (empty file)
+++ jifty/trunk/lib/Jifty/Manual/Actions.pod	Wed Jun 28 12:12:38 2006
@@ -0,0 +1,299 @@
+=head1 NAME
+Jifty::Manual::Actions - Doing Stuff With Jifty
+C<Jifty::Action> abstracts around the idea of taking named inputs
+(L<"arguments"|Jifty::Manual::Glossary/argument>), doing something
+with them, and returning some result to the user. If this sounds
+incredibly general, that's because it is -- actions do nearly
+B<everything> in Jifty.
+C<Jifty::Action> will also generate HTML for you for its arguments --
+no more manually writing C<< <input> >> tags and extracting GET and
+POST arguments by hand and dispatching them where they belong --
+C<Jifty::Action>> does it all for you.
+Jifty provides some actions for you out of the box -- see
+L<Jifty::Manual::ObjectModel> and L<Jifty::Action::Record> for
+autogenerated actions, as well as L<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
+I<AppName>::Action. Actions usually live in the I<AppName>::Action::
+namespace; While that's just 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 L<arguments|/arguments>, and a
+L</take_action> method.
+=head2 arguments
+Every C<Jifty::Action> subclass should define a C<sub arguments> that
+returns a hashref describing what arguments it takes. Supposing we
+were writing a an action to post a blog article, we might start out
+with arguments like thus:
+    sub arguments {
+        my $self = shift;
+        return { title    => {},
+                 category => {},
+                 body     => {} };
+    }
+However, we've only scratched the surface of the power the
+C<arguments> API offers. Arguments (can) have types, labels,
+validators, canonicalizers, and even more. To start with, lets add
+some types and labels:
+    sub arguments {
+        my $self = shift;
+        return {
+            title    => {
+                label     => "Title",
+                length    => 50,
+                mandatory => 1,
+            },
+            category => {
+                label     => "Category",
+                length    => 30,
+               },
+            body     => {
+                label     => "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 C<category> field, by making it a combobox (a combination
+dropdown/text field), with some default values available:
+   ...
+   category => {
+            label            => "Category",
+            render_as        => "Combobox",
+            available_values => ["Personal", "Work", "Blog"]
+        },
+   ...
+But a static list is lame. What we really want is a C<Category> model,
+and to keep track of all the categories users have entered:
+    ...
+    my $categories = MyBlog::Model::CategoryCollection->new();
+    $categories->unlimit;
+    ...
+        category => {
+            label            => "Category",
+            render_as        => "Select",
+            available_values => [
+                {
+                    display_from => 'name',
+                    value_from   => 'name',
+                    collection   => $categories
+                }
+            ]
+        },
+    ...
+Now, Jifty will populate the combox with the result of calling C<name>
+on each element on C<$categories>. Alternatively, if you set
+C<value_from => 'id'>, Jifty would automatically return the C<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 L<Jifty::Action> and L<Jifty::Web::Form::Field> for more fields
+you can set in the returned C<arguments> hash.
+=head3 validation
+C<Jifty::Action> can automatically validate arguments for you, as
+appropriate. If an argument has C<valid_values>, then C<Jifty::Action>
+will automatically verify that the given value matches one of
+them. However, you can also write your own validators. Just write a
+C<< sub validate_<argument> >>, 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');
+    }
+You can also do validation in the model -- see
+Note that if, instead of failing, you want to automatically modify
+invalid content to be valid, you want a
+L<canonicalizer|Jifty::Manual::Glossary/canonicalize>, not a
+Additionally, if you set C<ajax_validates> or C<ajax_canonicalizes> to
+true for an argument, then Jifty will automatically validate or
+canonicalize it in an L<AJAX|Jifty::Manual::Glossary/ajax>-enabled
+browser when the user stops typing.
+=head2 take_action
+Once an action has arguments, it needs to do something with them. An
+action does so in its C<take_action> sub, which will be called when an
+action is submitted, and only if its arguments
+Inside C<sub take_action>, subclasses can access their arguments via
+C<$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 C<$self->has_argument('foo')>.
+Once an action has done its thing, it needs to inform the caller
+whether or not it has succeeded, possibly with some status message. To
+this end, every C<Jifty::Action> has a C<Jifty::Result> associated
+with. C<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
+C<take_action>, write code like:
+    $self->result->error('Couldn't 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. 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. See
+L<Jifty::Request::Mapper> for some more information.
+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. L<Jifty::Request::add_action|Jifty::Request/add_action>,
+L<Jifty::Web::Form::add_action|Jifty::Web::Form/new_action>), will
+automatically qualify the C<class> with either C<Jifty::Action::> or
+C<I<AppName>::Action::> as necessary (I told you putting actions in
+I<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 L<dispatcher|Jifty::Dispatcher>, or a Mason
+component's C<< <%init%> >> block (See L</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->form->link(label => "Post", submit => # $create) %>
+    %# or <% $action->button(label => "Post"); %>
+    <% Jifty->web->form->end %>
+C<form_field> will render the field, along with the C<label> as an
+HTML C<< <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 C<< <div> >>s you can style
+using CSS. (TODO: Document Jifty HTML classes and default CSS).
+See L<Jifty::Web::Form/submit>, L<Jifty::Web/link> and
+L<Jifty::Action/button> for details on the different ways to generate
+a submit button.
+Additionally, instead of C<form_field>, you can use C<hidden> to
+generate a C<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
+L<ACLs|Jifty::Manual::AccessControl> in place. If it still worries
+you, you probably want a L<continuation|Jifty::Continuation>.
+=head3 monikers
+You probably noticed the C<<moniker => 'post_blog'>>. Every action you
+create in Jifty has an associated
+L<moniker|Jifty::Manual::Glossary>. A C<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
+C<dispatcher|Jifty::Dispatcher>. Monikers give us that. Given a
+moniker, you can pull information about the associated action out of a
+L<request|Jifty::Request> or L<response|Jifty::Response>.
+If a moniker is unspecified, it will be autogenerated.
+(XXX TODO Note about action registration here)
+=head3 Argument Folding
+If you write out more than one C<form_field> for a given argument in
+the same form, and more than one is filled in, Jifty will C<fold> the
+arguments into an array before filling them in to the action. This
+provides a way to do, e.g. a C<BulkEdit> action that applies some set
+of changes to many records at once.
+(XXX TODO Note about C<constructor> arguments)
+=head1 SEE ALSO
+L<Jifty::Action>, L<Jifty::Manual::Tutorial>

More information about the Jifty-commit mailing list