[Catalyst] The Definitive Guide to Catalyst ... p. 165 listing all users and their roles

Robyn Jonahs learn.catalyst at gmail.com
Wed Jul 11 16:43:46 GMT 2012


So Just to understand or get confirmation that I am understanding this
correctly...

When I use "user.user_roles" I am looking at the UserRole.pm result class.

Then when I look at that, I should use the belongs_to accessor to the
Role.pm result class not point at id for the Role in this table and it is
automagically taken care of.

So basically it needs to explicitly go to the join table and within that
join table point to the accessor to get the final "role" from the Role.pm
result class column.

I think that is correct. Look at the accessor in the join table not the
actual column name was the problem.




On Wed, Jul 11, 2012 at 12:29 PM, Robyn Jonahs <learn.catalyst at gmail.com>wr=
ote:

> Thanks, that worked. Now I am off to see why.
>
>
>
>
> On Wed, Jul 11, 2012 at 12:26 PM, fREW Schmidt <frioux at gmail.com> wrote:
>
>> Instead of role.role_id.role you should do role.role.role
>>
>> obviously that's silly in how confusing it is, so eventually if I were
>> you i'd make the column in the role table to be called name, and then
>> instead of calling user_roles role, call then user_role.  That would make
>> the above user_role.role.name.
>>
>> Sorry, for the top post, replying from my phone
>> On Jul 11, 2012 10:58 AM, "Robyn Jonahs" <learn.catalyst at gmail.com>
>> wrote:
>>
>>> Hi,
>>>
>>> I am working through the chapter in the book to learn about many to many
>>> relationship bridges.
>>>
>>> I have made it through the chapter up to the last part where it has us
>>> list all users and their roles. Page 165 in Chapter 6.
>>>
>>> This is the template file root/authusers/list.tt
>>>
>>> <html>
>>> <head>
>>>   <title>All users and their roles</title>
>>> </head>
>>> <body>
>>>
>>> <table>
>>>   <tr><th>UserID</th><th>
>>> Username</th><th>eMail</th><th>Roles</th></tr>
>>>   [% WHILE (user =3D users_rs.next) %]
>>>     <tr>
>>>       <td>[% user.id %]</td>
>>>       <td>[% user.username %]</td>
>>>       <td>[% user.email %]</td>
>>>       <td>
>>>         <ul>
>>>           [% FOREACH role =3D user.user_roles %]
>>>             <li>[% role.role_id.role %]</li>
>>>           [% END %]
>>>         </ul>
>>>       </td>
>>>     </tr>
>>>   [% END %]
>>> </table>
>>>
>>> </body>
>>> </html>
>>>
>>>
>>> If I remove the last "role" in the FOREACH loop it will list the id for
>>> the roles. It fails to list the text associated with the roles and I ca=
n't
>>> figure out what is going wrong. The only major difference between the b=
ook
>>> and what has happened for me locally is that DBIx::Class::Schema::Loader
>>> (version 0.07025 ) created the schema results as
>>>
>>> DBAuthTest$ ls lib/Auth/Schema/Result/
>>> Role.pm        User.pm        UserRole.pm
>>>
>>> Not the plurals as in the book (Roles.pm, User.pm and UserRoles.pm). I
>>> have been trying to track these names and keep it consistent with what =
I am
>>> doing as opposed to the book instructions and so far I have worked thro=
ugh
>>> it.
>>>
>>> The result gives the <li> dots but no values. So it is counting them
>>> correctly but not retrieving the values. I am stumped on this and any h=
elp
>>> at all would be greatly appreciated.
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> The other relevant files are:
>>> =3D=3D=3D=3D=3D=3D=3D=3D The Controller =3D=3D=3D=3D=3D=3D=3D=3D=3D
>>>
>>> lib/DBAuthTest/Controller/AuthUsers.pm
>>>
>>>
>>>
>>> package DBAuthTest::Controller::AuthUsers;
>>> use Moose;
>>> use namespace::autoclean;
>>>
>>> BEGIN {extends 'Catalyst::Controller'; }
>>>
>>> =3Dhead1 NAME
>>>
>>> DBAuthTest::Controller::AuthUsers - Catalyst Controller
>>>
>>> =3Dhead1 DESCRIPTION
>>>
>>> Catalyst Controller.
>>>
>>> =3Dhead1 METHODS
>>>
>>> =3Dcut
>>>
>>>
>>> =3Dhead2 index
>>>
>>> =3Dcut
>>>
>>> sub base : Chained('/'): PathPart('authusers'): CaptureArgs(0) {
>>>     my ( $self, $c ) =3D @_;
>>>
>>>     $c->stash(users_rs =3D> $c->model('AuthDB::User'));
>>>     $c->stash(roles_rs =3D> $c->model('AuthDB::Role'));
>>> }
>>>
>>>
>>> sub add : Chained('base'): PathPart('add'): Args(0) {
>>>   my ( $self, $c ) =3D @_;
>>>
>>>   if(lc $c->req->method eq 'post') {
>>>     my $params =3D $c->req->params;
>>>
>>>     ## Retrieve the users_rs stashed by the base action:
>>>     my $users_rs =3D $c->stash->{users_rs};
>>>
>>>     ## Create the user:
>>> =3Dhead2 Original Code
>>>   - keep for now as I don't trust the code below.
>>>
>>>     my $newuser =3D $users_rs->create({
>>>         username =3D> $params->{username},
>>>         email    =3D> $params->{email},
>>>         password =3D> $params->{password},
>>>     });
>>> =3Dcut
>>> =3Dhead2 Catching Errors
>>>   - No Workiee, not in their code either.
>>> =3Dcut
>>>     my $newuser =3D eval { $users_rs->create({
>>>       username =3D> $params->{username},
>>>       email    =3D> $params->{email},
>>>       password =3D> $params->{password},
>>>     }) };
>>>     if($@) {
>>>       $c->log->debug(
>>>         "User tried to sign up with an invalid email address,
>>> redoing...");
>>>       $c->stash( errors =3D> { email =3D> 'invalid' }, err =3D> $@ );
>>>       return;
>>>     }
>>>
>>>     return $c->res->redirect( $c->uri_for(
>>>         $c->controller('AuthUsers')->action_for('profile'),
>>>         [ $newuser->id ]
>>>     ) );
>>>
>>>   }
>>>
>>> }
>>>
>>>
>>> sub user : Chained('base'): PathPart(''): CaptureArgs(1) {
>>>   my ($self, $c, $userid) =3D @_;
>>>
>>>   my $user =3D $c->stash->{users_rs}->find({ id =3D> $userid },{ key =
=3D>
>>> 'primary' });
>>>
>>>   die "No such user" if(!$user);
>>>
>>>   $c->stash(user =3D> $user);
>>> }
>>>
>>>
>>> sub profile : Chained('user') :PathPart('profile'): Args(0) {
>>>   my ($self, $c) =3D @_;
>>>
>>> }
>>>
>>>
>>> sub edit : Chained('user') :PathPart('edit'): Args(0) {
>>>   my ($self, $c) =3D @_;
>>>
>>>   if(lc $c->req->method eq 'post') {
>>>     my $params =3D $c->req->params;
>>>     my $user    =3D $c->stash->{user};
>>>
>>>     ## Check user is allowed to update this profile
>>>     #if($c->user->object->id !=3D $user->id) {
>>>     #  die "Malicious attempt to update another user by: ".
>>> $c->user->username;
>>>     #}
>>>
>>>     ## Update user's email and/or password
>>>     $user->update({
>>>       email =3D> $params->{email},
>>>       password =3D> $params->{password},
>>>     });
>>>
>>>     ## Send the user back to the changed profile
>>>     return $c->res->redirect( $c->uri_for(
>>>       $c->controller('AuthUsers')->action_for('profile'), [ $user->id ]
>>> ) );
>>>   }
>>> }
>>>
>>>
>>> =3Dhead2 Original
>>> sub set_roles :Chained('user'): PathPart('set_roles'): Args() {
>>>   my ($self, $c) =3D @_;
>>>
>>>   my $user =3D $c->stash->{user};
>>>   if(lc $c->req->method eq 'post') {
>>>
>>>     ## Fetch all role ids submitted as a list
>>>     my @roles =3D $c->req->param('role');
>>>
>>>     ## Remove any existing roles, we're replacing them:
>>>     $user->user_roles->delete;
>>>
>>>     ## Add new roles:
>>>     foreach my $role_id (@roles) {
>>>       $user->user_roles->create({ role_id =3D> $role_id });
>>>     }
>>>   }
>>>
>>>
>>> $c->res->redirect($c->uri_for($c->controller()->action_for('profile'),[
>>> $user->id ] ));
>>> }
>>> =3Dcut
>>> sub set_roles :Chained('user'): PathPart('set_roles'): Args() {
>>>   my ($self, $c) =3D @_;
>>>
>>>   my $user =3D $c->stash->{user};
>>>   if(lc $c->req->method eq 'post') {
>>>
>>>     ## Fetch all role ids submitted as a list
>>>     my @roles =3D $c->req->param('role');
>>>
>>>     $user->set_all_roles(@roles);
>>>   }
>>>
>>>   $c->res->redirect($c->uri_for($c->controller()->action_for('profile'),
>>>     [ $user->id ] ));
>>> }
>>>
>>>
>>> sub delete :Chained('user'): PatPart('delete'): Args() {
>>>   my ($self, $c) =3D @_;
>>>   my $user =3D $c->stash->{user};
>>>   $user->delete();
>>>
>>>   return $c->res->redirect( $c->uri_for('/') );
>>> }
>>>
>>>
>>> sub list : Chained('base'): PathPart('list'): Args(0) {
>>>   my ($self, $c) =3D @_;
>>> }
>>>
>>> __PACKAGE__->meta->make_immutable;
>>>
>>> 1;
>>>
>>>
>>> ------- The Result Classes ------
>>> DBAuthTest$ ls lib/Auth/Schema/Result/
>>> Role.pm      User.pm      UserRole.pm
>>>
>>>
>>> =3D=3D=3D=3D=3D=3D=3D=3D User.pm =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D
>>> use utf8;
>>> package Auth::Schema::Result::User;
>>>
>>> # Created by DBIx::Class::Schema::Loader
>>> # DO NOT MODIFY THE FIRST PART OF THIS FILE
>>>
>>> =3Dhead1 NAME
>>>
>>> Auth::Schema::Result::User
>>>
>>> =3Dcut
>>>
>>> use strict;
>>> use warnings;
>>>
>>> use Moose;
>>> use MooseX::NonMoose;
>>> use MooseX::MarkAsMethods autoclean =3D> 1;
>>> extends 'DBIx::Class::Core';
>>>
>>> =3Dhead1 COMPONENTS LOADED
>>>
>>> =3Dover 4
>>>
>>> =3Ditem * L<DBIx::Class::InflateColumn::DateTime>
>>>
>>> =3Ditem * L<DBIx::Class::TimeStamp>
>>>
>>> =3Dback
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
>>>
>>> =3Dhead1 TABLE: C<users>
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->table("users");
>>>
>>> =3Dhead1 ACCESSORS
>>>
>>> =3Dhead2 id
>>>
>>>   data_type: 'integer'
>>>   is_auto_increment: 1
>>>   is_nullable: 0
>>>
>>> =3Dhead2 username
>>>
>>>   data_type: 'text'
>>>   is_nullable: 1
>>>
>>> =3Dhead2 email
>>>
>>>   data_type: 'text'
>>>   is_nullable: 1
>>>
>>> =3Dhead2 password
>>>
>>>   data_type: 'text'
>>>   is_nullable: 1
>>>
>>> =3Dhead2 last_modified
>>>
>>>   data_type: 'datetime'
>>>   is_nullable: 1
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->add_columns(
>>>   "id",
>>>   { data_type =3D> "integer", is_auto_increment =3D> 1, is_nullable =3D=
> 0 },
>>>   "username",
>>>   { data_type =3D> "text", is_nullable =3D> 1 },
>>>   "email",
>>>   { data_type =3D> "text", is_nullable =3D> 1 },
>>>   "password",
>>>   { data_type =3D> "text", is_nullable =3D> 1 },
>>>   "last_modified",
>>>   { data_type =3D> "datetime", is_nullable =3D> 1 },
>>> );
>>>
>>> =3Dhead1 PRIMARY KEY
>>>
>>> =3Dover 4
>>>
>>> =3Ditem * L</id>
>>>
>>> =3Dback
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->set_primary_key("id");
>>>
>>> =3Dhead1 UNIQUE CONSTRAINTS
>>>
>>> =3Dhead2 C<username_unique>
>>>
>>> =3Dover 4
>>>
>>> =3Ditem * L</username>
>>>
>>> =3Dback
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->add_unique_constraint("username_unique", ["username"]);
>>>
>>> =3Dhead1 RELATIONS
>>>
>>> =3Dhead2 user_roles
>>>
>>> Type: has_many
>>>
>>> Related object: L<Auth::Schema::Result::UserRole>
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->has_many(
>>>   "user_roles",
>>>   "Auth::Schema::Result::UserRole",
>>>   { "foreign.user_id" =3D> "self.id" },
>>>   { cascade_copy =3D> 0, cascade_delete =3D> 0 },
>>> );
>>>
>>> =3Dhead2 roles
>>>
>>> Type: many_to_many
>>>
>>> Composing rels: L</user_roles> -> role
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->many_to_many("roles", "user_roles", "role");
>>>
>>>
>>> # Created by DBIx::Class::Schema::Loader v0.07025 @ 2012-07-09 00:18:52
>>> # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:6svl+CkzndehZ8+Zp5yXhw
>>>
>>>
>>> # You can replace this text with custom code or comments, and it will be
>>> preserved on regeneration
>>> __PACKAGE__->meta->make_immutable;
>>>
>>> __PACKAGE__->add_columns('last_modified',
>>>   { %{__PACKAGE__->column_info('last_modified') },
>>>   set_on_create =3D> 1,
>>>   set_on_update =3D> 1
>>> });
>>>
>>>
>>> use Email::Valid;
>>> sub new {
>>>   my ($class, $args)=3D at _;
>>>
>>>   if( exists $args->{email} && !Email::Valid->address($args->{email}) )=
 {
>>>     die 'Email invalid';
>>>   }
>>>
>>>   return $class->next::method($args);
>>> }
>>>
>>>
>>> sub has_role {
>>>   my ($self, $role) =3D @_;
>>>
>>>   ## $role is a row object for a role
>>>
>>>   my $roles =3D $self->user_roles->find({ role_id =3D> $role->id });
>>>   return $roles;
>>>
>>> }
>>>
>>>
>>> sub set_all_roles {
>>>   my ($self, @roleids) =3D @_;
>>>
>>>   ## Remove any existing roles, we're replacing them:
>>>   $self->user_roles->delete;
>>>
>>>   ## Add new roles:
>>>   foreach my $role_id (@roleids) {
>>>     $self->user_roles->create({ role_id =3D> $role_id });
>>>   }
>>>
>>>   return $self;
>>> }
>>>
>>>
>>> 1;
>>>
>>>
>>>
>>> =3D=3D=3D=3D=3D=3D=3D=3D UserRole.pm =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D
>>>
>>>
>>> use utf8;
>>> package Auth::Schema::Result::UserRole;
>>>
>>> # Created by DBIx::Class::Schema::Loader
>>> # DO NOT MODIFY THE FIRST PART OF THIS FILE
>>>
>>> =3Dhead1 NAME
>>>
>>> Auth::Schema::Result::UserRole
>>>
>>> =3Dcut
>>>
>>> use strict;
>>> use warnings;
>>>
>>> use Moose;
>>> use MooseX::NonMoose;
>>> use MooseX::MarkAsMethods autoclean =3D> 1;
>>> extends 'DBIx::Class::Core';
>>>
>>> =3Dhead1 COMPONENTS LOADED
>>>
>>> =3Dover 4
>>>
>>> =3Ditem * L<DBIx::Class::InflateColumn::DateTime>
>>>
>>> =3Ditem * L<DBIx::Class::TimeStamp>
>>>
>>> =3Dback
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
>>>
>>> =3Dhead1 TABLE: C<user_roles>
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->table("user_roles");
>>>
>>> =3Dhead1 ACCESSORS
>>>
>>> =3Dhead2 user_id
>>>
>>>   data_type: 'integer'
>>>   is_foreign_key: 1
>>>   is_nullable: 0
>>>
>>> =3Dhead2 role_id
>>>
>>>   data_type: 'integer'
>>>   is_foreign_key: 1
>>>   is_nullable: 0
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->add_columns(
>>>   "user_id",
>>>   { data_type =3D> "integer", is_foreign_key =3D> 1, is_nullable =3D> 0=
 },
>>>   "role_id",
>>>   { data_type =3D> "integer", is_foreign_key =3D> 1, is_nullable =3D> 0=
 },
>>> );
>>>
>>> =3Dhead1 PRIMARY KEY
>>>
>>> =3Dover 4
>>>
>>> =3Ditem * L</user_id>
>>>
>>> =3Ditem * L</role_id>
>>>
>>> =3Dback
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->set_primary_key("user_id", "role_id");
>>>
>>> =3Dhead1 RELATIONS
>>>
>>> =3Dhead2 role
>>>
>>> Type: belongs_to
>>>
>>> Related object: L<Auth::Schema::Result::Role>
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->belongs_to(
>>>   "role",
>>>   "Auth::Schema::Result::Role",
>>>   { id =3D> "role_id" },
>>>   { is_deferrable =3D> 1, on_delete =3D> "CASCADE", on_update =3D> "CAS=
CADE" },
>>> );
>>>
>>> =3Dhead2 user
>>>
>>> Type: belongs_to
>>>
>>> Related object: L<Auth::Schema::Result::User>
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->belongs_to(
>>>   "user",
>>>   "Auth::Schema::Result::User",
>>>   { id =3D> "user_id" },
>>>   { is_deferrable =3D> 1, on_delete =3D> "CASCADE", on_update =3D> "CAS=
CADE" },
>>> );
>>>
>>>
>>> # Created by DBIx::Class::Schema::Loader v0.07025 @ 2012-07-09 00:18:52
>>> # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:0RYpPqJtXPb7IMPYjImDng
>>>
>>>
>>> # You can replace this text with custom code or comments, and it will be
>>> preserved on regeneration
>>> __PACKAGE__->meta->make_immutable;
>>> 1;
>>>
>>>
>>>
>>> =3D=3D=3D=3D=3D=3D=3D=3D Role.pm =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D
>>>
>>> use utf8;
>>> package Auth::Schema::Result::Role;
>>>
>>> # Created by DBIx::Class::Schema::Loader
>>> # DO NOT MODIFY THE FIRST PART OF THIS FILE
>>>
>>> =3Dhead1 NAME
>>>
>>> Auth::Schema::Result::Role
>>>
>>> =3Dcut
>>>
>>> use strict;
>>> use warnings;
>>>
>>> use Moose;
>>> use MooseX::NonMoose;
>>> use MooseX::MarkAsMethods autoclean =3D> 1;
>>> extends 'DBIx::Class::Core';
>>>
>>> =3Dhead1 COMPONENTS LOADED
>>>
>>> =3Dover 4
>>>
>>> =3Ditem * L<DBIx::Class::InflateColumn::DateTime>
>>>
>>> =3Ditem * L<DBIx::Class::TimeStamp>
>>>
>>> =3Dback
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
>>>
>>> =3Dhead1 TABLE: C<roles>
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->table("roles");
>>>
>>> =3Dhead1 ACCESSORS
>>>
>>> =3Dhead2 id
>>>
>>>   data_type: 'integer'
>>>   is_auto_increment: 1
>>>   is_nullable: 0
>>>
>>> =3Dhead2 role
>>>
>>>   data_type: 'text'
>>>   is_nullable: 1
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->add_columns(
>>>   "id",
>>>   { data_type =3D> "integer", is_auto_increment =3D> 1, is_nullable =3D=
> 0 },
>>>   "role",
>>>   { data_type =3D> "text", is_nullable =3D> 1 },
>>> );
>>>
>>> =3Dhead1 PRIMARY KEY
>>>
>>> =3Dover 4
>>>
>>> =3Ditem * L</id>
>>>
>>> =3Dback
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->set_primary_key("id");
>>>
>>> =3Dhead1 UNIQUE CONSTRAINTS
>>>
>>> =3Dhead2 C<role_unique>
>>>
>>> =3Dover 4
>>>
>>> =3Ditem * L</role>
>>>
>>> =3Dback
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->add_unique_constraint("role_unique", ["role"]);
>>>
>>> =3Dhead1 RELATIONS
>>>
>>> =3Dhead2 user_roles
>>>
>>> Type: has_many
>>>
>>> Related object: L<Auth::Schema::Result::UserRole>
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->has_many(
>>>   "user_roles",
>>>   "Auth::Schema::Result::UserRole",
>>>   { "foreign.role_id" =3D> "self.id" },
>>>   { cascade_copy =3D> 0, cascade_delete =3D> 0 },
>>> );
>>>
>>> =3Dhead2 users
>>>
>>> Type: many_to_many
>>>
>>> Composing rels: L</user_roles> -> user
>>>
>>> =3Dcut
>>>
>>> __PACKAGE__->many_to_many("users", "user_roles", "user");
>>>
>>>
>>> # Created by DBIx::Class::Schema::Loader v0.07025 @ 2012-07-09 00:18:52
>>> # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:a8Hd9uGBQmPWRsNQd8WR6Q
>>>
>>>
>>> # You can replace this text with custom code or comments, and it will be
>>> preserved on regeneration
>>> __PACKAGE__->meta->make_immutable;
>>> 1;
>>>
>>> _______________________________________________
>>> List: Catalyst at lists.scsys.co.uk
>>> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
>>> Searchable archive:
>>> http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
>>> Dev site: http://dev.catalyst.perl.org/
>>>
>>>
>> _______________________________________________
>> List: Catalyst at lists.scsys.co.uk
>> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
>> Searchable archive:
>> http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
>> Dev site: http://dev.catalyst.perl.org/
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20120711/411e5=
7e1/attachment.htm


More information about the Catalyst mailing list