Mojolicious

 view release on metacpan or  search on metacpan

lib/Mojolicious/Guides/Rendering.pod  view on Meta::CPAN

  % layout 'mylayout';
  % content_for header => begin
    <meta http-equiv="Content-Type" content="text/html">
  % end
  <div>Hello World!</div>
  % content_for header => begin
    <meta http-equiv="Pragma" content="no-cache">
  % end

  @@ layouts/mylayout.html.ep
  <!DOCTYPE html>
  <html>
    <head><%= content 'header' %></head>
    <body><%= content %></body>
  </html>

=head2 Forms

To build HTML forms more efficiently you can use tag helpers like L<Mojolicious::Plugin::TagHelpers/"form_for">, which
can automatically select a request method for you if a route name is provided. And since most browsers only allow forms
to be submitted with C<GET> and C<POST>, but not request methods like C<PUT> or C<DELETE>, they are spoofed with an
C<_method> query parameter.

  use Mojolicious::Lite -signatures;

  get '/' => 'form';

  # PUT  /nothing
  # POST /nothing?_method=PUT
  put '/nothing' => sub ($c) {

    # Prevent double form submission with redirect
    my $value = $c->param('whatever');
    $c->flash(confirmation => "We did nothing with your value ($value).");
    $c->redirect_to('form');
  };

  app->start;
  __DATA__

  @@ form.html.ep
  <!DOCTYPE html>
  <html>
    <body>
      % if (my $confirmation = flash 'confirmation') {
        <p><%= $confirmation %></p>
      % }
      %= form_for nothing => begin
        %= text_field whatever => 'I ♥ Mojolicious!'
        %= submit_button
      % end
    </body>
  </html>

The helpers L<Mojolicious::Plugin::DefaultHelpers/"flash"> and L<Mojolicious::Plugin::DefaultHelpers/"redirect_to"> are
often used together to prevent double form submission, allowing users to receive a confirmation message that will
vanish if they decide to reload the page they've been redirected to.

=head2 Form validation

You can use L<Mojolicious::Plugin::DefaultHelpers/"validation"> to validate C<GET> and C<POST> parameters submitted to
your application. All unknown fields will be ignored by default, so you have to decide which should be
L<required|Mojolicious::Validator::Validation/"required"> or L<optional|Mojolicious::Validator::Validation/"optional">
before you can perform checks on their values. Every check is performed right away, so you can use the results
immediately to build more advanced validation logic with methods like L<Mojolicious::Validator::Validation/"is_valid">.

  use Mojolicious::Lite -signatures;

  get '/' => sub ($c) {

    # Check if parameters have been submitted
    my $v = $c->validation;
    return $c->render('index') unless $v->has_data;

    # Validate parameters ("pass_again" depends on "pass")
    $v->required('user')->size(1, 20)->like(qr/^[a-z0-9]+$/);
    $v->required('pass_again')->equal_to('pass') if $v->optional('pass')->size(7, 500)->is_valid;

    # Check if validation failed
    return $c->render('index') if $v->has_error;

    # Render confirmation
    $c->render('thanks');
  };

  app->start;
  __DATA__

  @@ index.html.ep
  <!DOCTYPE html>
  <html>
    <head>
      <style>
        label.field-with-error { color: #dd7e5e }
        input.field-with-error { background-color: #fd9e7e }
      </style>
    </head>
    <body>
      %= form_for index => begin
        %= label_for user => 'Username (required, 1-20 characters, a-z/0-9)'
        <br>
        %= text_field 'user', id => 'user'
        %= submit_button
        <br>
        %= label_for pass => 'Password (optional, 7-500 characters)'
        <br>
        %= password_field 'pass', id => 'pass'
        <br>
        %= label_for pass_again => 'Password again (equal to the value above)'
        <br>
        %= password_field 'pass_again', id => 'pass_again'
      % end
    </body>
  </html>

  @@ thanks.html.ep
  <!DOCTYPE html>
  <html><body>Thank you <%= validation->param('user') %>.</body></html>

Form elements generated with tag helpers from L<Mojolicious::Plugin::TagHelpers> will automatically remember their
previous values and add the class C<field-with-error> for fields that failed validation to make styling with CSS

lib/Mojolicious/Guides/Rendering.pod  view on Meta::CPAN

  <input class="field-with-error" type="text" name="user" value="sri">

For a full list of available checks see also L<Mojolicious::Validator/"CHECKS">.

=head2 Adding form validation checks

Validation checks can be registered with L<Mojolicious::Validator/"add_check"> and return a false value if they were
successful. A true value may be used to pass along additional information which can then be retrieved with
L<Mojolicious::Validator::Validation/"error">.

  use Mojolicious::Lite -signatures;

  # Add "range" check
  app->validator->add_check(range => sub ($v, $name, $value, $min, $max) {
    return $value < $min || $value > $max;
  });

  get '/' => 'form';

  post '/test' => sub ($c) {

    # Validate parameters with custom check
    my $v = $c->validation;
    $v->required('number')->range(3, 23);

    # Render form again if validation failed
    return $c->render('form') if $v->has_error;

    # Prevent double form submission with redirect
    $c->flash(number => $v->param('number'));
    $c->redirect_to('form');
  };

  app->start;
  __DATA__

  @@ form.html.ep
  <!DOCTYPE html>
  <html>
    <body>
      % if (my $number = flash 'number') {
        <p>Thanks, the number <%= $number %> was valid.</p>
      % }
      %= form_for test => begin
        % if (my $err = validation->error('number')) {
          <p>
            %= 'Value is required.' if $err->[0] eq 'required'
            %= 'Value needs to be between 3 and 23.' if $err->[0] eq 'range'
          </p>
        % }
        %= text_field 'number'
        %= submit_button
      % end
    </body>
  </html>

=head2 Cross-site request forgery

CSRF is a very common attack on web applications that trick your logged in users to submit forms they did not intend to
send, with something as mundane as a link. All you have to do, to protect your users from this, is to add an additional
hidden field to your forms with L<Mojolicious::Plugin::TagHelpers/"csrf_field">, and validate it with
L<Mojolicious::Validator::Validation/"csrf_protect">.

  use Mojolicious::Lite -signatures;

  get '/' => {template => 'target'};

  post '/' => sub ($c) {

    # Check CSRF token
    my $v = $c->validation;
    return $c->render(text => 'Bad CSRF token!', status => 403) if $v->csrf_protect->has_error('csrf_token');

    my $city = $v->required('city')->param('city');
    $c->render(text => "Low orbit ion cannon pointed at $city!") unless $v->has_error;
  } => 'target';

  app->start;
  __DATA__

  @@ target.html.ep
  <!DOCTYPE html>
  <html>
    <body>
      %= form_for target => begin
        %= csrf_field
        %= label_for city => 'Which city to point low orbit ion cannon at?'
        %= text_field 'city', id => 'city'
        %= submit_button
      %= end
    </body>
  </html>

For Ajax requests and the like, you can also generate a token directly with the helper
L<Mojolicious::Plugin::DefaultHelpers/"csrf_token">, and then pass it along with the C<X-CSRF-Token> request header.

=head1 ADVANCED

Less commonly used and more powerful features.

=head2 Template inheritance

Inheritance takes the layout concept above one step further, the helpers
L<Mojolicious::Plugin::DefaultHelpers/"content"> and L<Mojolicious::Plugin::DefaultHelpers/"extends"> allow you to
build skeleton templates with named blocks that child templates can override.

  use Mojolicious::Lite;

  # first > mylayout
  get '/first' => {template => 'first', layout => 'mylayout'};

  # third > second > first > mylayout
  get '/third' => {template => 'third', layout => 'mylayout'};

  app->start;
  __DATA__

  @@ layouts/mylayout.html.ep
  <!DOCTYPE html>
  <html>
    <head><title>Hello</title></head>



( run in 0.558 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )