NAME
Jifty::Manual::Cookbook
DESCRIPTION
This document aims to provide solutions to common questions of "How do I do x with Jifty?" While the solutions here certainly aren't the only way to do things, they're generally the solutions the developers of Jifty use, and ones that work pretty well.
HOW DO I ...
Add Atom/RSS Feeds ?
You could generate atom/rss feeds for virtually any model in your application. For instance, suppose there's a "Post" model (like a blog entry), you could use XML::Feed to do this:
# In '/feed' template
<%args>
$type
</%args>
<%init>
use XML::Feed;
my $posts = MyApp::Model::PostCollection->new();
$posts->unlimit();
my $feed = XML::Feed->new( $type );
$feed->title( Jifty->config->framework('ApplicationName') . " Feed" );
$feed->link( Jifty->web->url );
$feed->description( $feed->title );
while( my $post = $posts->next ) {
my $feed_entry = XML::Feed::Entry->new($type);
$feed_entry->title($post->title);
$feed_entry->author($post->author->username);
$feed_entry->link( Jifty->web->url . "/posts/" . $post->id );
$feed_entry->issued( $post->created_on );
$feed_entry->summary( $post->body );
$feed->add_entry($feed_entry);
}
</%init>
<% $feed->as_xml |n%>
And add this in MyApp/Dispatcher.pm
to make URI look prettier:
on qr{^/feed/(atom|rss|rss2)}, run {
set type => $1;
show('/feed');
};
And of course, you need to put these in your HTML header tempalte (conventionally that's /_elements/header
):
<link rel="alternate" type="application/atom+xml" title="Atom" href="/feed/atom" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="/feed/rss" />
Use date or time objects with the database?
On your columns, specify either
filters are 'Jifty::DBI::Filter::DateTime'
for a timestamp (date and time), or
filters are 'Jifty::DBI::Filter::Date'
for just a date. Jifty will then automatically translate to and from DateTime objects for you when you access the column on your model. Additionally, if you add:
filters are qw(Jifty::Filter::DateTime Jifty::DBI::Filter::Date)
Jifty will inspect the model's current_user for a time_zone
method, and, if it exists, set the retrieved DateTime object's time zone appropriately. All dates are stored in UTC in the database, to ensure consistency.
How do I emulate 'created_on' field like Rails ?
In Rails, if you have a field named 'created_on', it's automatically set to the creation time of the record. How can I emulate this behaviour in Jifty ?
The trick here is to use Scalar::Defer. And declare your column like this:
column created_on =>
type is 'timestamp',
label is 'Created On',
default is defer { DateTime->now },
filters are 'Jifty::DBI::Filter::DateTime';
This approach is not really accurate, if you render this field in a form, then the defer value is evaluated by the time of rendering, which might be way eariler then the creation of record. However, it is the easiest one.
If you're using the newly recommeded JIfty::DBI::Record schema {}
to declare schema, you might find this trick not working at the moment. Please override model's before_create
method instead:
sub before_create {
my ($self, $attr) = @_;
$attr->{'created_on'} = DateTime->now;
};
Limit access to pages to logged-in users
The best place to do this is probably in your application's Dispatcher. If, for example, you wanted to limit access to /secret
to logged-in users, you could write:
before qr'^/secret' => run {
unless(Jifty->web->current_user->id) {
Jifty->web->tangent('/login');
}
};
Then, in your login form component, you would write something like:
<% Jifty->web->return(to => '/', submit => $login_action) $>
The combination of the tangent
and return
will cause the user to be returned to wherever they came from. See Jifty::Continuation for more information.
If you want model-level access control, Jifty provides a ready-built ACL system for its models; See Jifty::Manual::AccessControl for details.
Finally, you can also allow or deny specific actions in the dispatcher, to limit who is able to perform what actions -- see Jifty::API.
Run my Jifty app as fascgi in Apache/Lighttpd ?
Jifty provides a really simple way to run the application as a fastcgi server. The complete instruction and example is in 'jifty help fastcgi'
for both Apache server and Lighttpd server. (Please cd to your app dir before run this command.)
You'll have to install CGI::Fast
and FCGI
module for this.
Take actions based on data in URLs
You can add actions to the request based on data in URLs, or anything else, using Jifty::Request::add_action. For example, suppose you wanted to make the path /logout
log the user out, and redirect them to the home page. You could write:
before '/logout' => {
Jifty->web->request->add_action( class => 'Logout' );
Jifty->web->request->add_action( class => 'Redirect',
arguments => { url => '/' });
};
Pass HTML form input directly to components
Sometimes, you don't want to take an action based on input from HTML forms, but just want to change how the page is displayed, or do something similarly transient.
Jifty::Action
is great, but it doesn't have to be the answer to everything. For cases like this, it's fine to use typical HTML <input>s
. Their values will be accessible as request arguments, so you can fetch them with get
in the dispatcher, and they will be passed as arguments to top-level Mason components that list them in <%args>
. And don't worry about namespace conflicts with Jifty's auto-generated argument fields -- Jifty prefixes all its name
s with J:
so there won't be a problem.
Perform database migration
Edit etc/config.yaml and change Database->Version to a proper value (say, 0.0.2). Then run
jifty schema --setup
Jifty would inspect current database and perform proper actions. You could give a --print
option to see the actual SQL statement:
jifty schema --setup --print
Use different table names than the ones Jifty automatically creates
In YourApp::Record define a _guess_table_name sub that doesn't pluralises or pluralises differently.
How do I perform ajax canonicalization on a given field ?
Asking user to input something in a form is really common in a web app. For some certain form fields you want them to have a certain normalized/canonicalized form in database, and you could do an ajax canonicalization in Jifty very easily. Lets say your User model need a canonicalized username
field to make sure those names are in lowercase. All you have to do is to define a method named canonicalize_username
your Model class, like this:
package MyApp::Model::User;
use base qw(MyApp::Record);
sub canonicalize_username {
my $class = shift;
my $value = shift
return lc($value);
}
If the form is generated by a Jifty::Action::Record
-based action (all those autogenerated CRUD actions), then this is all you need to do. And that is probably 90% of the case. Jifty::Action::Record
would check if there is a method named like canonicalize_fieldname
when it is rendering form fields. If found, related javascript code is generated. You do not have to modify any code in your view. Jifty does it for you.
The ajax canonicalization happens when the input focus leaves that field. You would see the effect a bit latter that the value in the field is changed.