vendion has asked for the wisdom of the Perl Monks concerning the following question:

Per request of another Monk I am reposting my Catalyst question. I am new to Catalyst development and I am trying to create a View that displays the contents of a single table in my database, sort of like a "system users" page.
This is what I have in my controller:

sub base : Chained('/'): PathPart('admin'): CaptureArgs(0) { my ($self, $c) = @_; $c->stash( users_rs => $c->model('DB::Tech')); $c->log->debug('*** INSIDE BASE METHOD ***'); } sub list :Chained('base') :PathPart('list') :Args(0) { my ($self, $c) = @_; my ($users) = $c->model('DB::Tech')->search_rs; $c->stash( users => $users ); $c->stash(template => 'admin/list.tt2'); $c->log->debug("*** INSIDE LIST METHOD users = $users +***"); } sub create : Chained('base'): PathPart('create'): Args(0) { my ($self, $c) = @_; if(lc $c->req->method eq 'post') { # Retrieve the values fro mthe form my $params = $c->req->params; my $users_rs = $c->stash->{users_rs}; my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yd +ay, $isdst ) = localtime time; $year += 1900; my @month_abbr = qw( Jan Feb Mar Apr May Jun Jul Aug S +ep Oct Nov Dec ); my $date = "$year-$month_abbr[$mon]-$mday"; my $newuser = eval { $users_rs->create({ username => $params->{username}, password => $params->{password}, fname => $params->{fname}, lname => $params->{lname}, email => $params->{email}, phone => $params->{phone}, managementrating => '5', managementcomments => q[], date => $date, ismanagement => '0', }) }; if($@) { $c->log->debug( "Invalid email address in user creatio +n" ); $c->stash->{error_msg} = 'Invalid email addres +s in user creation'; return; } $Data::Dumper::Useperl = 1; } }

The create subroutine works and I am able to add new entries to my database, but the list doesn't display anything. Here is what I get from the Catalyst server:

[info] *** Request 1 (0.167/s) [19733] [Tue Mar 29 20:49:35 2011] *** + + + [debug] "GET" request for "admin/list" from "192.168.1.3" + + + [debug] Path is "/admin/list" + + + [debug] *** INSIDE BASE METHOD *** + + + [debug] *** INSIDE LIST METHOD users = 1 *** + + + [debug] Rendering template "admin/list.tt2" + + + [debug] Response Code: 200; Content-Type: text/html; charset=utf-8; Co +ntent-Length: 1546 + + [info] Request took 0.131545s (7.602/s)

Here is what my list.tt2 contains:

[% META title = 'System Users List' -%] <table> <tr><th>ID</th><th>firstname</th><th>lastname</th><th>email</th><th>ph +one</th><th>Management Rating</th><th>Comments</th><th>Date</th><th>A +dmin</th></tr> [% FOR tech IN users.all -%] <tr> <td>[% users.id %]</td> <td>[% users.firstname %]</td> <td>[% users.lastname %]</td> <td>[% users.phone %]</td> <td>[% users.email %]</td> <td>[% users.phone %]</td> <td>[% users.managementrating %]</td> <td>[% users.managementcomments %]</td> <td>[% users.date %]</td> <td>[% users.ismanagement %]</td> </tr> [% END -%] </table> <pre> Dump of the 'users' variable: [% Dumper.dump(users) %] </pre>

Replies are listed 'Best First'.
Re: Can't retrieve data in a catalyst controller
by Your Mother (Archbishop) on Mar 30, 2011 at 04:18 UTC

    This is a little fishy–

    my ($users) = $c->model('DB::Tech')->search_rs; # No parens necessary or desired, it returns just a ResultSet. my $users = $c->model('DB::Tech')->search_rs;

    –but it won’t cause a problem either way.

    Debugging / general pointers–

    • Take the $c->log->debug("*** INSIDE… messages out. If you run the dev server with the debug flag, it’ll report the dispatch paths and such. Do not leave -Debug in your MyApp.pm if it is still there.
    • Remove the users stuff from admin/list completely.
    • ALWAYS escape user provided data in templates. If you don’t, the terrorists win.

    New controller method (PathPart is fine to be explicit but it is redundant here because it’s the same as the method name; and the template setting might even be superfluous)–

    sub list :Chained('base') :Args(0) { my ( $self, $c ) = @_; $c->stash(template => 'admin/list.tt2'); } # OR this is likely to work if your TT stuff is configured right- sub list :Chained('base') :Args(0) {}

    Now the template. Compare the var names in the loop below to your version. users_rs is already in the stash from chaining off of admin/base. You might want to stop referring to them as techs. It does seem to cause some problems. :)

    [% META title = 'System Users List' -%] <table> <tr><th>ID</th><th>firstname</th><th>lastname</th><th>email</th><th>ph +one</th><th>Management Rating</th><th>Comments</th><th>Date</th><th>A +dmin</th></tr> [% FOR user IN users_rs.all -%] <tr> <td>[% user.id %]</td> <td>[% user.firstname | html %]</td> <td>[% user.lastname | html %]</td> <td>[% user.phone | html %]</td> <td>[% user.email | html %]</td> <td>[% user.phone | html %]</td> <td>[% user.managementrating | html %]</td> <td>[% user.managementcomments | html %]</td> <td>[% user.date %]</td> <td>[% user.ismanagement %]</td> </tr> [% END -%] </table>

      Thank you for the help, it is working now.

      Ok so one question I have is in the template why did it matter when the for loop was called as [% FOR user IN users_rs.all -%] I'm just trying to understand why it had to be 'user' when I am not setting anything like this in my code. I am trying to understand so I will know for future reference. I can't seem to find a good answer to this anywhere

        It doesn't have to be $user.

        FOR user IN users_rs.all
        is like
        for my $user (users_rs->all)

        What ikegami said, plus make sure to read your original code–

        [% FOR tech IN users.all -%] <tr> <td>[% users.id %]</td>

        The problem is you called each object in the resultset tech but tried to access it as users. This would be fine too–

        [% FOR tech IN users.all -%] <tr> <td>[% tech.id %]</td>

        I was joking above about keeping it consistent (always calling them user) because it has led to confusion a couple of times, not that tech is somehow wrong.