Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Catalyst: Users

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

 

 

Catalyst users RSS feed   Index | Next | Previous | View Threaded


learn.catalyst at gmail

Jul 11, 2012, 8:58 AM

Post #1 of 7 (232 views)
Permalink
The Definitive Guide to Catalyst ... p. 165 listing all users and their roles

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 = users_rs.next) %]
<tr>
<td>[% user.id %]</td>
<td>[% user.username %]</td>
<td>[% user.email %]</td>
<td>
<ul>
[% FOREACH role = 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 can't
figure out what is going wrong. The only major difference between the book
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 through
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 help
at all would be greatly appreciated.







The other relevant files are:
======== The Controller =========

lib/DBAuthTest/Controller/AuthUsers.pm



package DBAuthTest::Controller::AuthUsers;
use Moose;
use namespace::autoclean;

BEGIN {extends 'Catalyst::Controller'; }

=head1 NAME

DBAuthTest::Controller::AuthUsers - Catalyst Controller

=head1 DESCRIPTION

Catalyst Controller.

=head1 METHODS

=cut


=head2 index

=cut

sub base : Chained('/'): PathPart('authusers'): CaptureArgs(0) {
my ( $self, $c ) = @_;

$c->stash(users_rs => $c->model('AuthDB::User'));
$c->stash(roles_rs => $c->model('AuthDB::Role'));
}


sub add : Chained('base'): PathPart('add'): Args(0) {
my ( $self, $c ) = @_;

if(lc $c->req->method eq 'post') {
my $params = $c->req->params;

## Retrieve the users_rs stashed by the base action:
my $users_rs = $c->stash->{users_rs};

## Create the user:
=head2 Original Code
- keep for now as I don't trust the code below.

my $newuser = $users_rs->create({
username => $params->{username},
email => $params->{email},
password => $params->{password},
});
=cut
=head2 Catching Errors
- No Workiee, not in their code either.
=cut
my $newuser = eval { $users_rs->create({
username => $params->{username},
email => $params->{email},
password => $params->{password},
}) };
if($@) {
$c->log->debug(
"User tried to sign up with an invalid email address, redoing...");
$c->stash( errors => { email => 'invalid' }, err => $@ );
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) = @_;

my $user = $c->stash->{users_rs}->find({ id => $userid },{ key =>
'primary' });

die "No such user" if(!$user);

$c->stash(user => $user);
}


sub profile : Chained('user') :PathPart('profile'): Args(0) {
my ($self, $c) = @_;

}


sub edit : Chained('user') :PathPart('edit'): Args(0) {
my ($self, $c) = @_;

if(lc $c->req->method eq 'post') {
my $params = $c->req->params;
my $user = $c->stash->{user};

## Check user is allowed to update this profile
#if($c->user->object->id != $user->id) {
# die "Malicious attempt to update another user by: ".
$c->user->username;
#}

## Update user's email and/or password
$user->update({
email => $params->{email},
password => $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 ] ) );
}
}


=head2 Original
sub set_roles :Chained('user'): PathPart('set_roles'): Args() {
my ($self, $c) = @_;

my $user = $c->stash->{user};
if(lc $c->req->method eq 'post') {

## Fetch all role ids submitted as a list
my @roles = $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 => $role_id });
}
}

$c->res->redirect($c->uri_for($c->controller()->action_for('profile'),[
$user->id ] ));
}
=cut
sub set_roles :Chained('user'): PathPart('set_roles'): Args() {
my ($self, $c) = @_;

my $user = $c->stash->{user};
if(lc $c->req->method eq 'post') {

## Fetch all role ids submitted as a list
my @roles = $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) = @_;
my $user = $c->stash->{user};
$user->delete();

return $c->res->redirect( $c->uri_for('/') );
}


sub list : Chained('base'): PathPart('list'): Args(0) {
my ($self, $c) = @_;
}

__PACKAGE__->meta->make_immutable;

1;


------- The Result Classes ------
DBAuthTest$ ls lib/Auth/Schema/Result/
Role.pm User.pm UserRole.pm


======== User.pm =============
use utf8;
package Auth::Schema::Result::User;

# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE

=head1 NAME

Auth::Schema::Result::User

=cut

use strict;
use warnings;

use Moose;
use MooseX::NonMoose;
use MooseX::MarkAsMethods autoclean => 1;
extends 'DBIx::Class::Core';

=head1 COMPONENTS LOADED

=over 4

=item * L<DBIx::Class::InflateColumn::DateTime>

=item * L<DBIx::Class::TimeStamp>

=back

=cut

__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");

=head1 TABLE: C<users>

=cut

__PACKAGE__->table("users");

=head1 ACCESSORS

=head2 id

data_type: 'integer'
is_auto_increment: 1
is_nullable: 0

=head2 username

data_type: 'text'
is_nullable: 1

=head2 email

data_type: 'text'
is_nullable: 1

=head2 password

data_type: 'text'
is_nullable: 1

=head2 last_modified

data_type: 'datetime'
is_nullable: 1

=cut

__PACKAGE__->add_columns(
"id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"username",
{ data_type => "text", is_nullable => 1 },
"email",
{ data_type => "text", is_nullable => 1 },
"password",
{ data_type => "text", is_nullable => 1 },
"last_modified",
{ data_type => "datetime", is_nullable => 1 },
);

=head1 PRIMARY KEY

=over 4

=item * L</id>

=back

=cut

__PACKAGE__->set_primary_key("id");

=head1 UNIQUE CONSTRAINTS

=head2 C<username_unique>

=over 4

=item * L</username>

=back

=cut

__PACKAGE__->add_unique_constraint("username_unique", ["username"]);

=head1 RELATIONS

=head2 user_roles

Type: has_many

Related object: L<Auth::Schema::Result::UserRole>

=cut

__PACKAGE__->has_many(
"user_roles",
"Auth::Schema::Result::UserRole",
{ "foreign.user_id" => "self.id" },
{ cascade_copy => 0, cascade_delete => 0 },
);

=head2 roles

Type: many_to_many

Composing rels: L</user_roles> -> role

=cut

__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 => 1,
set_on_update => 1
});


use Email::Valid;
sub new {
my ($class, $args)=@_;

if( exists $args->{email} && !Email::Valid->address($args->{email}) ) {
die 'Email invalid';
}

return $class->next::method($args);
}


sub has_role {
my ($self, $role) = @_;

## $role is a row object for a role

my $roles = $self->user_roles->find({ role_id => $role->id });
return $roles;

}


sub set_all_roles {
my ($self, @roleids) = @_;

## 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 => $role_id });
}

return $self;
}


1;



======== UserRole.pm =============


use utf8;
package Auth::Schema::Result::UserRole;

# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE

=head1 NAME

Auth::Schema::Result::UserRole

=cut

use strict;
use warnings;

use Moose;
use MooseX::NonMoose;
use MooseX::MarkAsMethods autoclean => 1;
extends 'DBIx::Class::Core';

=head1 COMPONENTS LOADED

=over 4

=item * L<DBIx::Class::InflateColumn::DateTime>

=item * L<DBIx::Class::TimeStamp>

=back

=cut

__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");

=head1 TABLE: C<user_roles>

=cut

__PACKAGE__->table("user_roles");

=head1 ACCESSORS

=head2 user_id

data_type: 'integer'
is_foreign_key: 1
is_nullable: 0

=head2 role_id

data_type: 'integer'
is_foreign_key: 1
is_nullable: 0

=cut

__PACKAGE__->add_columns(
"user_id",
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
"role_id",
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
);

=head1 PRIMARY KEY

=over 4

=item * L</user_id>

=item * L</role_id>

=back

=cut

__PACKAGE__->set_primary_key("user_id", "role_id");

=head1 RELATIONS

=head2 role

Type: belongs_to

Related object: L<Auth::Schema::Result::Role>

=cut

__PACKAGE__->belongs_to(
"role",
"Auth::Schema::Result::Role",
{ id => "role_id" },
{ is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
);

=head2 user

Type: belongs_to

Related object: L<Auth::Schema::Result::User>

=cut

__PACKAGE__->belongs_to(
"user",
"Auth::Schema::Result::User",
{ id => "user_id" },
{ is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
);


# 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;



======== Role.pm =============

use utf8;
package Auth::Schema::Result::Role;

# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE

=head1 NAME

Auth::Schema::Result::Role

=cut

use strict;
use warnings;

use Moose;
use MooseX::NonMoose;
use MooseX::MarkAsMethods autoclean => 1;
extends 'DBIx::Class::Core';

=head1 COMPONENTS LOADED

=over 4

=item * L<DBIx::Class::InflateColumn::DateTime>

=item * L<DBIx::Class::TimeStamp>

=back

=cut

__PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");

=head1 TABLE: C<roles>

=cut

__PACKAGE__->table("roles");

=head1 ACCESSORS

=head2 id

data_type: 'integer'
is_auto_increment: 1
is_nullable: 0

=head2 role

data_type: 'text'
is_nullable: 1

=cut

__PACKAGE__->add_columns(
"id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"role",
{ data_type => "text", is_nullable => 1 },
);

=head1 PRIMARY KEY

=over 4

=item * L</id>

=back

=cut

__PACKAGE__->set_primary_key("id");

=head1 UNIQUE CONSTRAINTS

=head2 C<role_unique>

=over 4

=item * L</role>

=back

=cut

__PACKAGE__->add_unique_constraint("role_unique", ["role"]);

=head1 RELATIONS

=head2 user_roles

Type: has_many

Related object: L<Auth::Schema::Result::UserRole>

=cut

__PACKAGE__->has_many(
"user_roles",
"Auth::Schema::Result::UserRole",
{ "foreign.role_id" => "self.id" },
{ cascade_copy => 0, cascade_delete => 0 },
);

=head2 users

Type: many_to_many

Composing rels: L</user_roles> -> user

=cut

__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;


frioux at gmail

Jul 11, 2012, 9:26 AM

Post #2 of 7 (225 views)
Permalink
Re: The Definitive Guide to Catalyst ... p. 165 listing all users and their roles [In reply to]

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> 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 = users_rs.next) %]
> <tr>
> <td>[% user.id %]</td>
> <td>[% user.username %]</td>
> <td>[% user.email %]</td>
> <td>
> <ul>
> [% FOREACH role = 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 can't
> figure out what is going wrong. The only major difference between the book
> 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 through
> 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 help
> at all would be greatly appreciated.
>
>
>
>
>
>
>
> The other relevant files are:
> ======== The Controller =========
>
> lib/DBAuthTest/Controller/AuthUsers.pm
>
>
>
> package DBAuthTest::Controller::AuthUsers;
> use Moose;
> use namespace::autoclean;
>
> BEGIN {extends 'Catalyst::Controller'; }
>
> =head1 NAME
>
> DBAuthTest::Controller::AuthUsers - Catalyst Controller
>
> =head1 DESCRIPTION
>
> Catalyst Controller.
>
> =head1 METHODS
>
> =cut
>
>
> =head2 index
>
> =cut
>
> sub base : Chained('/'): PathPart('authusers'): CaptureArgs(0) {
> my ( $self, $c ) = @_;
>
> $c->stash(users_rs => $c->model('AuthDB::User'));
> $c->stash(roles_rs => $c->model('AuthDB::Role'));
> }
>
>
> sub add : Chained('base'): PathPart('add'): Args(0) {
> my ( $self, $c ) = @_;
>
> if(lc $c->req->method eq 'post') {
> my $params = $c->req->params;
>
> ## Retrieve the users_rs stashed by the base action:
> my $users_rs = $c->stash->{users_rs};
>
> ## Create the user:
> =head2 Original Code
> - keep for now as I don't trust the code below.
>
> my $newuser = $users_rs->create({
> username => $params->{username},
> email => $params->{email},
> password => $params->{password},
> });
> =cut
> =head2 Catching Errors
> - No Workiee, not in their code either.
> =cut
> my $newuser = eval { $users_rs->create({
> username => $params->{username},
> email => $params->{email},
> password => $params->{password},
> }) };
> if($@) {
> $c->log->debug(
> "User tried to sign up with an invalid email address, redoing...");
> $c->stash( errors => { email => 'invalid' }, err => $@ );
> 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) = @_;
>
> my $user = $c->stash->{users_rs}->find({ id => $userid },{ key =>
> 'primary' });
>
> die "No such user" if(!$user);
>
> $c->stash(user => $user);
> }
>
>
> sub profile : Chained('user') :PathPart('profile'): Args(0) {
> my ($self, $c) = @_;
>
> }
>
>
> sub edit : Chained('user') :PathPart('edit'): Args(0) {
> my ($self, $c) = @_;
>
> if(lc $c->req->method eq 'post') {
> my $params = $c->req->params;
> my $user = $c->stash->{user};
>
> ## Check user is allowed to update this profile
> #if($c->user->object->id != $user->id) {
> # die "Malicious attempt to update another user by: ".
> $c->user->username;
> #}
>
> ## Update user's email and/or password
> $user->update({
> email => $params->{email},
> password => $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 ] )
> );
> }
> }
>
>
> =head2 Original
> sub set_roles :Chained('user'): PathPart('set_roles'): Args() {
> my ($self, $c) = @_;
>
> my $user = $c->stash->{user};
> if(lc $c->req->method eq 'post') {
>
> ## Fetch all role ids submitted as a list
> my @roles = $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 => $role_id });
> }
> }
>
> $c->res->redirect($c->uri_for($c->controller()->action_for('profile'),[
> $user->id ] ));
> }
> =cut
> sub set_roles :Chained('user'): PathPart('set_roles'): Args() {
> my ($self, $c) = @_;
>
> my $user = $c->stash->{user};
> if(lc $c->req->method eq 'post') {
>
> ## Fetch all role ids submitted as a list
> my @roles = $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) = @_;
> my $user = $c->stash->{user};
> $user->delete();
>
> return $c->res->redirect( $c->uri_for('/') );
> }
>
>
> sub list : Chained('base'): PathPart('list'): Args(0) {
> my ($self, $c) = @_;
> }
>
> __PACKAGE__->meta->make_immutable;
>
> 1;
>
>
> ------- The Result Classes ------
> DBAuthTest$ ls lib/Auth/Schema/Result/
> Role.pm User.pm UserRole.pm
>
>
> ======== User.pm =============
> use utf8;
> package Auth::Schema::Result::User;
>
> # Created by DBIx::Class::Schema::Loader
> # DO NOT MODIFY THE FIRST PART OF THIS FILE
>
> =head1 NAME
>
> Auth::Schema::Result::User
>
> =cut
>
> use strict;
> use warnings;
>
> use Moose;
> use MooseX::NonMoose;
> use MooseX::MarkAsMethods autoclean => 1;
> extends 'DBIx::Class::Core';
>
> =head1 COMPONENTS LOADED
>
> =over 4
>
> =item * L<DBIx::Class::InflateColumn::DateTime>
>
> =item * L<DBIx::Class::TimeStamp>
>
> =back
>
> =cut
>
> __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
>
> =head1 TABLE: C<users>
>
> =cut
>
> __PACKAGE__->table("users");
>
> =head1 ACCESSORS
>
> =head2 id
>
> data_type: 'integer'
> is_auto_increment: 1
> is_nullable: 0
>
> =head2 username
>
> data_type: 'text'
> is_nullable: 1
>
> =head2 email
>
> data_type: 'text'
> is_nullable: 1
>
> =head2 password
>
> data_type: 'text'
> is_nullable: 1
>
> =head2 last_modified
>
> data_type: 'datetime'
> is_nullable: 1
>
> =cut
>
> __PACKAGE__->add_columns(
> "id",
> { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
> "username",
> { data_type => "text", is_nullable => 1 },
> "email",
> { data_type => "text", is_nullable => 1 },
> "password",
> { data_type => "text", is_nullable => 1 },
> "last_modified",
> { data_type => "datetime", is_nullable => 1 },
> );
>
> =head1 PRIMARY KEY
>
> =over 4
>
> =item * L</id>
>
> =back
>
> =cut
>
> __PACKAGE__->set_primary_key("id");
>
> =head1 UNIQUE CONSTRAINTS
>
> =head2 C<username_unique>
>
> =over 4
>
> =item * L</username>
>
> =back
>
> =cut
>
> __PACKAGE__->add_unique_constraint("username_unique", ["username"]);
>
> =head1 RELATIONS
>
> =head2 user_roles
>
> Type: has_many
>
> Related object: L<Auth::Schema::Result::UserRole>
>
> =cut
>
> __PACKAGE__->has_many(
> "user_roles",
> "Auth::Schema::Result::UserRole",
> { "foreign.user_id" => "self.id" },
> { cascade_copy => 0, cascade_delete => 0 },
> );
>
> =head2 roles
>
> Type: many_to_many
>
> Composing rels: L</user_roles> -> role
>
> =cut
>
> __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 => 1,
> set_on_update => 1
> });
>
>
> use Email::Valid;
> sub new {
> my ($class, $args)=@_;
>
> if( exists $args->{email} && !Email::Valid->address($args->{email}) ) {
> die 'Email invalid';
> }
>
> return $class->next::method($args);
> }
>
>
> sub has_role {
> my ($self, $role) = @_;
>
> ## $role is a row object for a role
>
> my $roles = $self->user_roles->find({ role_id => $role->id });
> return $roles;
>
> }
>
>
> sub set_all_roles {
> my ($self, @roleids) = @_;
>
> ## 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 => $role_id });
> }
>
> return $self;
> }
>
>
> 1;
>
>
>
> ======== UserRole.pm =============
>
>
> use utf8;
> package Auth::Schema::Result::UserRole;
>
> # Created by DBIx::Class::Schema::Loader
> # DO NOT MODIFY THE FIRST PART OF THIS FILE
>
> =head1 NAME
>
> Auth::Schema::Result::UserRole
>
> =cut
>
> use strict;
> use warnings;
>
> use Moose;
> use MooseX::NonMoose;
> use MooseX::MarkAsMethods autoclean => 1;
> extends 'DBIx::Class::Core';
>
> =head1 COMPONENTS LOADED
>
> =over 4
>
> =item * L<DBIx::Class::InflateColumn::DateTime>
>
> =item * L<DBIx::Class::TimeStamp>
>
> =back
>
> =cut
>
> __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
>
> =head1 TABLE: C<user_roles>
>
> =cut
>
> __PACKAGE__->table("user_roles");
>
> =head1 ACCESSORS
>
> =head2 user_id
>
> data_type: 'integer'
> is_foreign_key: 1
> is_nullable: 0
>
> =head2 role_id
>
> data_type: 'integer'
> is_foreign_key: 1
> is_nullable: 0
>
> =cut
>
> __PACKAGE__->add_columns(
> "user_id",
> { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
> "role_id",
> { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
> );
>
> =head1 PRIMARY KEY
>
> =over 4
>
> =item * L</user_id>
>
> =item * L</role_id>
>
> =back
>
> =cut
>
> __PACKAGE__->set_primary_key("user_id", "role_id");
>
> =head1 RELATIONS
>
> =head2 role
>
> Type: belongs_to
>
> Related object: L<Auth::Schema::Result::Role>
>
> =cut
>
> __PACKAGE__->belongs_to(
> "role",
> "Auth::Schema::Result::Role",
> { id => "role_id" },
> { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
> );
>
> =head2 user
>
> Type: belongs_to
>
> Related object: L<Auth::Schema::Result::User>
>
> =cut
>
> __PACKAGE__->belongs_to(
> "user",
> "Auth::Schema::Result::User",
> { id => "user_id" },
> { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
> );
>
>
> # 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;
>
>
>
> ======== Role.pm =============
>
> use utf8;
> package Auth::Schema::Result::Role;
>
> # Created by DBIx::Class::Schema::Loader
> # DO NOT MODIFY THE FIRST PART OF THIS FILE
>
> =head1 NAME
>
> Auth::Schema::Result::Role
>
> =cut
>
> use strict;
> use warnings;
>
> use Moose;
> use MooseX::NonMoose;
> use MooseX::MarkAsMethods autoclean => 1;
> extends 'DBIx::Class::Core';
>
> =head1 COMPONENTS LOADED
>
> =over 4
>
> =item * L<DBIx::Class::InflateColumn::DateTime>
>
> =item * L<DBIx::Class::TimeStamp>
>
> =back
>
> =cut
>
> __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
>
> =head1 TABLE: C<roles>
>
> =cut
>
> __PACKAGE__->table("roles");
>
> =head1 ACCESSORS
>
> =head2 id
>
> data_type: 'integer'
> is_auto_increment: 1
> is_nullable: 0
>
> =head2 role
>
> data_type: 'text'
> is_nullable: 1
>
> =cut
>
> __PACKAGE__->add_columns(
> "id",
> { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
> "role",
> { data_type => "text", is_nullable => 1 },
> );
>
> =head1 PRIMARY KEY
>
> =over 4
>
> =item * L</id>
>
> =back
>
> =cut
>
> __PACKAGE__->set_primary_key("id");
>
> =head1 UNIQUE CONSTRAINTS
>
> =head2 C<role_unique>
>
> =over 4
>
> =item * L</role>
>
> =back
>
> =cut
>
> __PACKAGE__->add_unique_constraint("role_unique", ["role"]);
>
> =head1 RELATIONS
>
> =head2 user_roles
>
> Type: has_many
>
> Related object: L<Auth::Schema::Result::UserRole>
>
> =cut
>
> __PACKAGE__->has_many(
> "user_roles",
> "Auth::Schema::Result::UserRole",
> { "foreign.role_id" => "self.id" },
> { cascade_copy => 0, cascade_delete => 0 },
> );
>
> =head2 users
>
> Type: many_to_many
>
> Composing rels: L</user_roles> -> user
>
> =cut
>
> __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
> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
> Searchable archive:
> http://www.mail-archive.com/catalyst [at] lists/
> Dev site: http://dev.catalyst.perl.org/
>
>


learn.catalyst at gmail

Jul 11, 2012, 9:29 AM

Post #3 of 7 (224 views)
Permalink
Re: The Definitive Guide to Catalyst ... p. 165 listing all users and their roles [In reply to]

Thanks, that worked. Now I am off to see why.



On Wed, Jul 11, 2012 at 12:26 PM, fREW Schmidt <frioux [at] gmail> 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> 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 = users_rs.next) %]
>> <tr>
>> <td>[% user.id %]</td>
>> <td>[% user.username %]</td>
>> <td>[% user.email %]</td>
>> <td>
>> <ul>
>> [% FOREACH role = 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 can't
>> figure out what is going wrong. The only major difference between the book
>> 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 through
>> 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 help
>> at all would be greatly appreciated.
>>
>>
>>
>>
>>
>>
>>
>> The other relevant files are:
>> ======== The Controller =========
>>
>> lib/DBAuthTest/Controller/AuthUsers.pm
>>
>>
>>
>> package DBAuthTest::Controller::AuthUsers;
>> use Moose;
>> use namespace::autoclean;
>>
>> BEGIN {extends 'Catalyst::Controller'; }
>>
>> =head1 NAME
>>
>> DBAuthTest::Controller::AuthUsers - Catalyst Controller
>>
>> =head1 DESCRIPTION
>>
>> Catalyst Controller.
>>
>> =head1 METHODS
>>
>> =cut
>>
>>
>> =head2 index
>>
>> =cut
>>
>> sub base : Chained('/'): PathPart('authusers'): CaptureArgs(0) {
>> my ( $self, $c ) = @_;
>>
>> $c->stash(users_rs => $c->model('AuthDB::User'));
>> $c->stash(roles_rs => $c->model('AuthDB::Role'));
>> }
>>
>>
>> sub add : Chained('base'): PathPart('add'): Args(0) {
>> my ( $self, $c ) = @_;
>>
>> if(lc $c->req->method eq 'post') {
>> my $params = $c->req->params;
>>
>> ## Retrieve the users_rs stashed by the base action:
>> my $users_rs = $c->stash->{users_rs};
>>
>> ## Create the user:
>> =head2 Original Code
>> - keep for now as I don't trust the code below.
>>
>> my $newuser = $users_rs->create({
>> username => $params->{username},
>> email => $params->{email},
>> password => $params->{password},
>> });
>> =cut
>> =head2 Catching Errors
>> - No Workiee, not in their code either.
>> =cut
>> my $newuser = eval { $users_rs->create({
>> username => $params->{username},
>> email => $params->{email},
>> password => $params->{password},
>> }) };
>> if($@) {
>> $c->log->debug(
>> "User tried to sign up with an invalid email address,
>> redoing...");
>> $c->stash( errors => { email => 'invalid' }, err => $@ );
>> 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) = @_;
>>
>> my $user = $c->stash->{users_rs}->find({ id => $userid },{ key =>
>> 'primary' });
>>
>> die "No such user" if(!$user);
>>
>> $c->stash(user => $user);
>> }
>>
>>
>> sub profile : Chained('user') :PathPart('profile'): Args(0) {
>> my ($self, $c) = @_;
>>
>> }
>>
>>
>> sub edit : Chained('user') :PathPart('edit'): Args(0) {
>> my ($self, $c) = @_;
>>
>> if(lc $c->req->method eq 'post') {
>> my $params = $c->req->params;
>> my $user = $c->stash->{user};
>>
>> ## Check user is allowed to update this profile
>> #if($c->user->object->id != $user->id) {
>> # die "Malicious attempt to update another user by: ".
>> $c->user->username;
>> #}
>>
>> ## Update user's email and/or password
>> $user->update({
>> email => $params->{email},
>> password => $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 ] )
>> );
>> }
>> }
>>
>>
>> =head2 Original
>> sub set_roles :Chained('user'): PathPart('set_roles'): Args() {
>> my ($self, $c) = @_;
>>
>> my $user = $c->stash->{user};
>> if(lc $c->req->method eq 'post') {
>>
>> ## Fetch all role ids submitted as a list
>> my @roles = $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 => $role_id });
>> }
>> }
>>
>> $c->res->redirect($c->uri_for($c->controller()->action_for('profile'),[
>> $user->id ] ));
>> }
>> =cut
>> sub set_roles :Chained('user'): PathPart('set_roles'): Args() {
>> my ($self, $c) = @_;
>>
>> my $user = $c->stash->{user};
>> if(lc $c->req->method eq 'post') {
>>
>> ## Fetch all role ids submitted as a list
>> my @roles = $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) = @_;
>> my $user = $c->stash->{user};
>> $user->delete();
>>
>> return $c->res->redirect( $c->uri_for('/') );
>> }
>>
>>
>> sub list : Chained('base'): PathPart('list'): Args(0) {
>> my ($self, $c) = @_;
>> }
>>
>> __PACKAGE__->meta->make_immutable;
>>
>> 1;
>>
>>
>> ------- The Result Classes ------
>> DBAuthTest$ ls lib/Auth/Schema/Result/
>> Role.pm User.pm UserRole.pm
>>
>>
>> ======== User.pm =============
>> use utf8;
>> package Auth::Schema::Result::User;
>>
>> # Created by DBIx::Class::Schema::Loader
>> # DO NOT MODIFY THE FIRST PART OF THIS FILE
>>
>> =head1 NAME
>>
>> Auth::Schema::Result::User
>>
>> =cut
>>
>> use strict;
>> use warnings;
>>
>> use Moose;
>> use MooseX::NonMoose;
>> use MooseX::MarkAsMethods autoclean => 1;
>> extends 'DBIx::Class::Core';
>>
>> =head1 COMPONENTS LOADED
>>
>> =over 4
>>
>> =item * L<DBIx::Class::InflateColumn::DateTime>
>>
>> =item * L<DBIx::Class::TimeStamp>
>>
>> =back
>>
>> =cut
>>
>> __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
>>
>> =head1 TABLE: C<users>
>>
>> =cut
>>
>> __PACKAGE__->table("users");
>>
>> =head1 ACCESSORS
>>
>> =head2 id
>>
>> data_type: 'integer'
>> is_auto_increment: 1
>> is_nullable: 0
>>
>> =head2 username
>>
>> data_type: 'text'
>> is_nullable: 1
>>
>> =head2 email
>>
>> data_type: 'text'
>> is_nullable: 1
>>
>> =head2 password
>>
>> data_type: 'text'
>> is_nullable: 1
>>
>> =head2 last_modified
>>
>> data_type: 'datetime'
>> is_nullable: 1
>>
>> =cut
>>
>> __PACKAGE__->add_columns(
>> "id",
>> { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
>> "username",
>> { data_type => "text", is_nullable => 1 },
>> "email",
>> { data_type => "text", is_nullable => 1 },
>> "password",
>> { data_type => "text", is_nullable => 1 },
>> "last_modified",
>> { data_type => "datetime", is_nullable => 1 },
>> );
>>
>> =head1 PRIMARY KEY
>>
>> =over 4
>>
>> =item * L</id>
>>
>> =back
>>
>> =cut
>>
>> __PACKAGE__->set_primary_key("id");
>>
>> =head1 UNIQUE CONSTRAINTS
>>
>> =head2 C<username_unique>
>>
>> =over 4
>>
>> =item * L</username>
>>
>> =back
>>
>> =cut
>>
>> __PACKAGE__->add_unique_constraint("username_unique", ["username"]);
>>
>> =head1 RELATIONS
>>
>> =head2 user_roles
>>
>> Type: has_many
>>
>> Related object: L<Auth::Schema::Result::UserRole>
>>
>> =cut
>>
>> __PACKAGE__->has_many(
>> "user_roles",
>> "Auth::Schema::Result::UserRole",
>> { "foreign.user_id" => "self.id" },
>> { cascade_copy => 0, cascade_delete => 0 },
>> );
>>
>> =head2 roles
>>
>> Type: many_to_many
>>
>> Composing rels: L</user_roles> -> role
>>
>> =cut
>>
>> __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 => 1,
>> set_on_update => 1
>> });
>>
>>
>> use Email::Valid;
>> sub new {
>> my ($class, $args)=@_;
>>
>> if( exists $args->{email} && !Email::Valid->address($args->{email}) ) {
>> die 'Email invalid';
>> }
>>
>> return $class->next::method($args);
>> }
>>
>>
>> sub has_role {
>> my ($self, $role) = @_;
>>
>> ## $role is a row object for a role
>>
>> my $roles = $self->user_roles->find({ role_id => $role->id });
>> return $roles;
>>
>> }
>>
>>
>> sub set_all_roles {
>> my ($self, @roleids) = @_;
>>
>> ## 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 => $role_id });
>> }
>>
>> return $self;
>> }
>>
>>
>> 1;
>>
>>
>>
>> ======== UserRole.pm =============
>>
>>
>> use utf8;
>> package Auth::Schema::Result::UserRole;
>>
>> # Created by DBIx::Class::Schema::Loader
>> # DO NOT MODIFY THE FIRST PART OF THIS FILE
>>
>> =head1 NAME
>>
>> Auth::Schema::Result::UserRole
>>
>> =cut
>>
>> use strict;
>> use warnings;
>>
>> use Moose;
>> use MooseX::NonMoose;
>> use MooseX::MarkAsMethods autoclean => 1;
>> extends 'DBIx::Class::Core';
>>
>> =head1 COMPONENTS LOADED
>>
>> =over 4
>>
>> =item * L<DBIx::Class::InflateColumn::DateTime>
>>
>> =item * L<DBIx::Class::TimeStamp>
>>
>> =back
>>
>> =cut
>>
>> __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
>>
>> =head1 TABLE: C<user_roles>
>>
>> =cut
>>
>> __PACKAGE__->table("user_roles");
>>
>> =head1 ACCESSORS
>>
>> =head2 user_id
>>
>> data_type: 'integer'
>> is_foreign_key: 1
>> is_nullable: 0
>>
>> =head2 role_id
>>
>> data_type: 'integer'
>> is_foreign_key: 1
>> is_nullable: 0
>>
>> =cut
>>
>> __PACKAGE__->add_columns(
>> "user_id",
>> { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
>> "role_id",
>> { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
>> );
>>
>> =head1 PRIMARY KEY
>>
>> =over 4
>>
>> =item * L</user_id>
>>
>> =item * L</role_id>
>>
>> =back
>>
>> =cut
>>
>> __PACKAGE__->set_primary_key("user_id", "role_id");
>>
>> =head1 RELATIONS
>>
>> =head2 role
>>
>> Type: belongs_to
>>
>> Related object: L<Auth::Schema::Result::Role>
>>
>> =cut
>>
>> __PACKAGE__->belongs_to(
>> "role",
>> "Auth::Schema::Result::Role",
>> { id => "role_id" },
>> { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
>> );
>>
>> =head2 user
>>
>> Type: belongs_to
>>
>> Related object: L<Auth::Schema::Result::User>
>>
>> =cut
>>
>> __PACKAGE__->belongs_to(
>> "user",
>> "Auth::Schema::Result::User",
>> { id => "user_id" },
>> { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
>> );
>>
>>
>> # 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;
>>
>>
>>
>> ======== Role.pm =============
>>
>> use utf8;
>> package Auth::Schema::Result::Role;
>>
>> # Created by DBIx::Class::Schema::Loader
>> # DO NOT MODIFY THE FIRST PART OF THIS FILE
>>
>> =head1 NAME
>>
>> Auth::Schema::Result::Role
>>
>> =cut
>>
>> use strict;
>> use warnings;
>>
>> use Moose;
>> use MooseX::NonMoose;
>> use MooseX::MarkAsMethods autoclean => 1;
>> extends 'DBIx::Class::Core';
>>
>> =head1 COMPONENTS LOADED
>>
>> =over 4
>>
>> =item * L<DBIx::Class::InflateColumn::DateTime>
>>
>> =item * L<DBIx::Class::TimeStamp>
>>
>> =back
>>
>> =cut
>>
>> __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
>>
>> =head1 TABLE: C<roles>
>>
>> =cut
>>
>> __PACKAGE__->table("roles");
>>
>> =head1 ACCESSORS
>>
>> =head2 id
>>
>> data_type: 'integer'
>> is_auto_increment: 1
>> is_nullable: 0
>>
>> =head2 role
>>
>> data_type: 'text'
>> is_nullable: 1
>>
>> =cut
>>
>> __PACKAGE__->add_columns(
>> "id",
>> { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
>> "role",
>> { data_type => "text", is_nullable => 1 },
>> );
>>
>> =head1 PRIMARY KEY
>>
>> =over 4
>>
>> =item * L</id>
>>
>> =back
>>
>> =cut
>>
>> __PACKAGE__->set_primary_key("id");
>>
>> =head1 UNIQUE CONSTRAINTS
>>
>> =head2 C<role_unique>
>>
>> =over 4
>>
>> =item * L</role>
>>
>> =back
>>
>> =cut
>>
>> __PACKAGE__->add_unique_constraint("role_unique", ["role"]);
>>
>> =head1 RELATIONS
>>
>> =head2 user_roles
>>
>> Type: has_many
>>
>> Related object: L<Auth::Schema::Result::UserRole>
>>
>> =cut
>>
>> __PACKAGE__->has_many(
>> "user_roles",
>> "Auth::Schema::Result::UserRole",
>> { "foreign.role_id" => "self.id" },
>> { cascade_copy => 0, cascade_delete => 0 },
>> );
>>
>> =head2 users
>>
>> Type: many_to_many
>>
>> Composing rels: L</user_roles> -> user
>>
>> =cut
>>
>> __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
>> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
>> Searchable archive:
>> http://www.mail-archive.com/catalyst [at] lists/
>> Dev site: http://dev.catalyst.perl.org/
>>
>>
> _______________________________________________
> List: Catalyst [at] lists
> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
> Searchable archive:
> http://www.mail-archive.com/catalyst [at] lists/
> Dev site: http://dev.catalyst.perl.org/
>
>


learn.catalyst at gmail

Jul 11, 2012, 9:43 AM

Post #4 of 7 (228 views)
Permalink
Re: The Definitive Guide to Catalyst ... p. 165 listing all users and their roles [In reply to]

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>wrote:

> Thanks, that worked. Now I am off to see why.
>
>
>
>
> On Wed, Jul 11, 2012 at 12:26 PM, fREW Schmidt <frioux [at] gmail> 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>
>> 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 = users_rs.next) %]
>>> <tr>
>>> <td>[% user.id %]</td>
>>> <td>[% user.username %]</td>
>>> <td>[% user.email %]</td>
>>> <td>
>>> <ul>
>>> [% FOREACH role = 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 can't
>>> figure out what is going wrong. The only major difference between the book
>>> 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 through
>>> 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 help
>>> at all would be greatly appreciated.
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> The other relevant files are:
>>> ======== The Controller =========
>>>
>>> lib/DBAuthTest/Controller/AuthUsers.pm
>>>
>>>
>>>
>>> package DBAuthTest::Controller::AuthUsers;
>>> use Moose;
>>> use namespace::autoclean;
>>>
>>> BEGIN {extends 'Catalyst::Controller'; }
>>>
>>> =head1 NAME
>>>
>>> DBAuthTest::Controller::AuthUsers - Catalyst Controller
>>>
>>> =head1 DESCRIPTION
>>>
>>> Catalyst Controller.
>>>
>>> =head1 METHODS
>>>
>>> =cut
>>>
>>>
>>> =head2 index
>>>
>>> =cut
>>>
>>> sub base : Chained('/'): PathPart('authusers'): CaptureArgs(0) {
>>> my ( $self, $c ) = @_;
>>>
>>> $c->stash(users_rs => $c->model('AuthDB::User'));
>>> $c->stash(roles_rs => $c->model('AuthDB::Role'));
>>> }
>>>
>>>
>>> sub add : Chained('base'): PathPart('add'): Args(0) {
>>> my ( $self, $c ) = @_;
>>>
>>> if(lc $c->req->method eq 'post') {
>>> my $params = $c->req->params;
>>>
>>> ## Retrieve the users_rs stashed by the base action:
>>> my $users_rs = $c->stash->{users_rs};
>>>
>>> ## Create the user:
>>> =head2 Original Code
>>> - keep for now as I don't trust the code below.
>>>
>>> my $newuser = $users_rs->create({
>>> username => $params->{username},
>>> email => $params->{email},
>>> password => $params->{password},
>>> });
>>> =cut
>>> =head2 Catching Errors
>>> - No Workiee, not in their code either.
>>> =cut
>>> my $newuser = eval { $users_rs->create({
>>> username => $params->{username},
>>> email => $params->{email},
>>> password => $params->{password},
>>> }) };
>>> if($@) {
>>> $c->log->debug(
>>> "User tried to sign up with an invalid email address,
>>> redoing...");
>>> $c->stash( errors => { email => 'invalid' }, err => $@ );
>>> 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) = @_;
>>>
>>> my $user = $c->stash->{users_rs}->find({ id => $userid },{ key =>
>>> 'primary' });
>>>
>>> die "No such user" if(!$user);
>>>
>>> $c->stash(user => $user);
>>> }
>>>
>>>
>>> sub profile : Chained('user') :PathPart('profile'): Args(0) {
>>> my ($self, $c) = @_;
>>>
>>> }
>>>
>>>
>>> sub edit : Chained('user') :PathPart('edit'): Args(0) {
>>> my ($self, $c) = @_;
>>>
>>> if(lc $c->req->method eq 'post') {
>>> my $params = $c->req->params;
>>> my $user = $c->stash->{user};
>>>
>>> ## Check user is allowed to update this profile
>>> #if($c->user->object->id != $user->id) {
>>> # die "Malicious attempt to update another user by: ".
>>> $c->user->username;
>>> #}
>>>
>>> ## Update user's email and/or password
>>> $user->update({
>>> email => $params->{email},
>>> password => $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 ]
>>> ) );
>>> }
>>> }
>>>
>>>
>>> =head2 Original
>>> sub set_roles :Chained('user'): PathPart('set_roles'): Args() {
>>> my ($self, $c) = @_;
>>>
>>> my $user = $c->stash->{user};
>>> if(lc $c->req->method eq 'post') {
>>>
>>> ## Fetch all role ids submitted as a list
>>> my @roles = $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 => $role_id });
>>> }
>>> }
>>>
>>>
>>> $c->res->redirect($c->uri_for($c->controller()->action_for('profile'),[
>>> $user->id ] ));
>>> }
>>> =cut
>>> sub set_roles :Chained('user'): PathPart('set_roles'): Args() {
>>> my ($self, $c) = @_;
>>>
>>> my $user = $c->stash->{user};
>>> if(lc $c->req->method eq 'post') {
>>>
>>> ## Fetch all role ids submitted as a list
>>> my @roles = $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) = @_;
>>> my $user = $c->stash->{user};
>>> $user->delete();
>>>
>>> return $c->res->redirect( $c->uri_for('/') );
>>> }
>>>
>>>
>>> sub list : Chained('base'): PathPart('list'): Args(0) {
>>> my ($self, $c) = @_;
>>> }
>>>
>>> __PACKAGE__->meta->make_immutable;
>>>
>>> 1;
>>>
>>>
>>> ------- The Result Classes ------
>>> DBAuthTest$ ls lib/Auth/Schema/Result/
>>> Role.pm User.pm UserRole.pm
>>>
>>>
>>> ======== User.pm =============
>>> use utf8;
>>> package Auth::Schema::Result::User;
>>>
>>> # Created by DBIx::Class::Schema::Loader
>>> # DO NOT MODIFY THE FIRST PART OF THIS FILE
>>>
>>> =head1 NAME
>>>
>>> Auth::Schema::Result::User
>>>
>>> =cut
>>>
>>> use strict;
>>> use warnings;
>>>
>>> use Moose;
>>> use MooseX::NonMoose;
>>> use MooseX::MarkAsMethods autoclean => 1;
>>> extends 'DBIx::Class::Core';
>>>
>>> =head1 COMPONENTS LOADED
>>>
>>> =over 4
>>>
>>> =item * L<DBIx::Class::InflateColumn::DateTime>
>>>
>>> =item * L<DBIx::Class::TimeStamp>
>>>
>>> =back
>>>
>>> =cut
>>>
>>> __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
>>>
>>> =head1 TABLE: C<users>
>>>
>>> =cut
>>>
>>> __PACKAGE__->table("users");
>>>
>>> =head1 ACCESSORS
>>>
>>> =head2 id
>>>
>>> data_type: 'integer'
>>> is_auto_increment: 1
>>> is_nullable: 0
>>>
>>> =head2 username
>>>
>>> data_type: 'text'
>>> is_nullable: 1
>>>
>>> =head2 email
>>>
>>> data_type: 'text'
>>> is_nullable: 1
>>>
>>> =head2 password
>>>
>>> data_type: 'text'
>>> is_nullable: 1
>>>
>>> =head2 last_modified
>>>
>>> data_type: 'datetime'
>>> is_nullable: 1
>>>
>>> =cut
>>>
>>> __PACKAGE__->add_columns(
>>> "id",
>>> { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
>>> "username",
>>> { data_type => "text", is_nullable => 1 },
>>> "email",
>>> { data_type => "text", is_nullable => 1 },
>>> "password",
>>> { data_type => "text", is_nullable => 1 },
>>> "last_modified",
>>> { data_type => "datetime", is_nullable => 1 },
>>> );
>>>
>>> =head1 PRIMARY KEY
>>>
>>> =over 4
>>>
>>> =item * L</id>
>>>
>>> =back
>>>
>>> =cut
>>>
>>> __PACKAGE__->set_primary_key("id");
>>>
>>> =head1 UNIQUE CONSTRAINTS
>>>
>>> =head2 C<username_unique>
>>>
>>> =over 4
>>>
>>> =item * L</username>
>>>
>>> =back
>>>
>>> =cut
>>>
>>> __PACKAGE__->add_unique_constraint("username_unique", ["username"]);
>>>
>>> =head1 RELATIONS
>>>
>>> =head2 user_roles
>>>
>>> Type: has_many
>>>
>>> Related object: L<Auth::Schema::Result::UserRole>
>>>
>>> =cut
>>>
>>> __PACKAGE__->has_many(
>>> "user_roles",
>>> "Auth::Schema::Result::UserRole",
>>> { "foreign.user_id" => "self.id" },
>>> { cascade_copy => 0, cascade_delete => 0 },
>>> );
>>>
>>> =head2 roles
>>>
>>> Type: many_to_many
>>>
>>> Composing rels: L</user_roles> -> role
>>>
>>> =cut
>>>
>>> __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 => 1,
>>> set_on_update => 1
>>> });
>>>
>>>
>>> use Email::Valid;
>>> sub new {
>>> my ($class, $args)=@_;
>>>
>>> if( exists $args->{email} && !Email::Valid->address($args->{email}) ) {
>>> die 'Email invalid';
>>> }
>>>
>>> return $class->next::method($args);
>>> }
>>>
>>>
>>> sub has_role {
>>> my ($self, $role) = @_;
>>>
>>> ## $role is a row object for a role
>>>
>>> my $roles = $self->user_roles->find({ role_id => $role->id });
>>> return $roles;
>>>
>>> }
>>>
>>>
>>> sub set_all_roles {
>>> my ($self, @roleids) = @_;
>>>
>>> ## 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 => $role_id });
>>> }
>>>
>>> return $self;
>>> }
>>>
>>>
>>> 1;
>>>
>>>
>>>
>>> ======== UserRole.pm =============
>>>
>>>
>>> use utf8;
>>> package Auth::Schema::Result::UserRole;
>>>
>>> # Created by DBIx::Class::Schema::Loader
>>> # DO NOT MODIFY THE FIRST PART OF THIS FILE
>>>
>>> =head1 NAME
>>>
>>> Auth::Schema::Result::UserRole
>>>
>>> =cut
>>>
>>> use strict;
>>> use warnings;
>>>
>>> use Moose;
>>> use MooseX::NonMoose;
>>> use MooseX::MarkAsMethods autoclean => 1;
>>> extends 'DBIx::Class::Core';
>>>
>>> =head1 COMPONENTS LOADED
>>>
>>> =over 4
>>>
>>> =item * L<DBIx::Class::InflateColumn::DateTime>
>>>
>>> =item * L<DBIx::Class::TimeStamp>
>>>
>>> =back
>>>
>>> =cut
>>>
>>> __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
>>>
>>> =head1 TABLE: C<user_roles>
>>>
>>> =cut
>>>
>>> __PACKAGE__->table("user_roles");
>>>
>>> =head1 ACCESSORS
>>>
>>> =head2 user_id
>>>
>>> data_type: 'integer'
>>> is_foreign_key: 1
>>> is_nullable: 0
>>>
>>> =head2 role_id
>>>
>>> data_type: 'integer'
>>> is_foreign_key: 1
>>> is_nullable: 0
>>>
>>> =cut
>>>
>>> __PACKAGE__->add_columns(
>>> "user_id",
>>> { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
>>> "role_id",
>>> { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
>>> );
>>>
>>> =head1 PRIMARY KEY
>>>
>>> =over 4
>>>
>>> =item * L</user_id>
>>>
>>> =item * L</role_id>
>>>
>>> =back
>>>
>>> =cut
>>>
>>> __PACKAGE__->set_primary_key("user_id", "role_id");
>>>
>>> =head1 RELATIONS
>>>
>>> =head2 role
>>>
>>> Type: belongs_to
>>>
>>> Related object: L<Auth::Schema::Result::Role>
>>>
>>> =cut
>>>
>>> __PACKAGE__->belongs_to(
>>> "role",
>>> "Auth::Schema::Result::Role",
>>> { id => "role_id" },
>>> { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
>>> );
>>>
>>> =head2 user
>>>
>>> Type: belongs_to
>>>
>>> Related object: L<Auth::Schema::Result::User>
>>>
>>> =cut
>>>
>>> __PACKAGE__->belongs_to(
>>> "user",
>>> "Auth::Schema::Result::User",
>>> { id => "user_id" },
>>> { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
>>> );
>>>
>>>
>>> # 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;
>>>
>>>
>>>
>>> ======== Role.pm =============
>>>
>>> use utf8;
>>> package Auth::Schema::Result::Role;
>>>
>>> # Created by DBIx::Class::Schema::Loader
>>> # DO NOT MODIFY THE FIRST PART OF THIS FILE
>>>
>>> =head1 NAME
>>>
>>> Auth::Schema::Result::Role
>>>
>>> =cut
>>>
>>> use strict;
>>> use warnings;
>>>
>>> use Moose;
>>> use MooseX::NonMoose;
>>> use MooseX::MarkAsMethods autoclean => 1;
>>> extends 'DBIx::Class::Core';
>>>
>>> =head1 COMPONENTS LOADED
>>>
>>> =over 4
>>>
>>> =item * L<DBIx::Class::InflateColumn::DateTime>
>>>
>>> =item * L<DBIx::Class::TimeStamp>
>>>
>>> =back
>>>
>>> =cut
>>>
>>> __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp");
>>>
>>> =head1 TABLE: C<roles>
>>>
>>> =cut
>>>
>>> __PACKAGE__->table("roles");
>>>
>>> =head1 ACCESSORS
>>>
>>> =head2 id
>>>
>>> data_type: 'integer'
>>> is_auto_increment: 1
>>> is_nullable: 0
>>>
>>> =head2 role
>>>
>>> data_type: 'text'
>>> is_nullable: 1
>>>
>>> =cut
>>>
>>> __PACKAGE__->add_columns(
>>> "id",
>>> { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
>>> "role",
>>> { data_type => "text", is_nullable => 1 },
>>> );
>>>
>>> =head1 PRIMARY KEY
>>>
>>> =over 4
>>>
>>> =item * L</id>
>>>
>>> =back
>>>
>>> =cut
>>>
>>> __PACKAGE__->set_primary_key("id");
>>>
>>> =head1 UNIQUE CONSTRAINTS
>>>
>>> =head2 C<role_unique>
>>>
>>> =over 4
>>>
>>> =item * L</role>
>>>
>>> =back
>>>
>>> =cut
>>>
>>> __PACKAGE__->add_unique_constraint("role_unique", ["role"]);
>>>
>>> =head1 RELATIONS
>>>
>>> =head2 user_roles
>>>
>>> Type: has_many
>>>
>>> Related object: L<Auth::Schema::Result::UserRole>
>>>
>>> =cut
>>>
>>> __PACKAGE__->has_many(
>>> "user_roles",
>>> "Auth::Schema::Result::UserRole",
>>> { "foreign.role_id" => "self.id" },
>>> { cascade_copy => 0, cascade_delete => 0 },
>>> );
>>>
>>> =head2 users
>>>
>>> Type: many_to_many
>>>
>>> Composing rels: L</user_roles> -> user
>>>
>>> =cut
>>>
>>> __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
>>> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
>>> Searchable archive:
>>> http://www.mail-archive.com/catalyst [at] lists/
>>> Dev site: http://dev.catalyst.perl.org/
>>>
>>>
>> _______________________________________________
>> List: Catalyst [at] lists
>> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
>> Searchable archive:
>> http://www.mail-archive.com/catalyst [at] lists/
>> Dev site: http://dev.catalyst.perl.org/
>>
>>
>


tja824 at gmail

Jul 11, 2012, 9:48 AM

Post #5 of 7 (232 views)
Permalink
Re: The Definitive Guide to Catalyst ... p. 165 listing all users and their roles [In reply to]

<li>[% role.role.role %]</li> works because you're accessing the role name
(the third 'role') through the 'role' accessor (the second 'role') which is
defined in your many-to-many relationship:

__PACKAGE__->many_to_many("roles", "user_roles", *"role"*);

This is one of the beauties of DBIC; as soon as you have your relationships
defined, you have paths to the data you need. Imagine trying to write the
same type of request across a multiple key relationship.


-Tim


On Wed, Jul 11, 2012 at 11:29 AM, Robyn Jonahs <learn.catalyst [at] gmail>wrote:

> Thanks, that worked. Now I am off to see why.
>
> [ snip ]
>


learn.catalyst at gmail

Jul 11, 2012, 11:25 AM

Post #6 of 7 (227 views)
Permalink
Re: The Definitive Guide to Catalyst ... p. 165 listing all users and their roles [In reply to]

Thanks Tim,

I thought that the many_to_many was a relationship bridge and as limited to
what it could do. I was studying the many_to_Many examples in the book to
help my real problem in a test application I am trying to work on. I guess
I should start a new thread for questions related to that. I will do that
and try to continue understanding the relationships.

Thanks
RJ

On Wed, Jul 11, 2012 at 12:48 PM, Tim Anderson <tja824 [at] gmail> wrote:

>
> <li>[% role.role.role %]</li> works because you're accessing the role
> name (the third 'role') through the 'role' accessor (the second 'role')
> which is defined in your many-to-many relationship:
>
> __PACKAGE__->many_to_many("roles", "user_roles", *"role"*);
>
> This is one of the beauties of DBIC; as soon as you have your
> relationships defined, you have paths to the data you need. Imagine trying
> to write the same type of request across a multiple key relationship.
>
>
> -Tim
>
>
> On Wed, Jul 11, 2012 at 11:29 AM, Robyn Jonahs <learn.catalyst [at] gmail>wrote:
>
>> Thanks, that worked. Now I am off to see why.
>>
>> [ snip ]
>>
>
> _______________________________________________
> List: Catalyst [at] lists
> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
> Searchable archive:
> http://www.mail-archive.com/catalyst [at] lists/
> Dev site: http://dev.catalyst.perl.org/
>
>


tja824 at gmail

Jul 11, 2012, 11:57 AM

Post #7 of 7 (225 views)
Permalink
Re: The Definitive Guide to Catalyst ... p. 165 listing all users and their roles [In reply to]

Sorry Robyn (and others I may have misled), I'm wrong.

I reviewed again, and you're not leveraging the many_to_many at all.
You're following a path that looks like this:

[% FOREACH role = user.user_roles %]

User.pm has a 'has_many' relationship called 'user_roles' that you are
leveraging, in each iteration of this loop role is set to a a UserRole row
object.


<li>[% role.role.role %]</li>

UserRole row object has 'belongs_to' relationship called 'role' (the second
'role' in the TT string above. This is why fREW's answer works.
Originally, using role_id accessed the value of role_id column in the
UserRole row, but you need to go one level deeper, so you use the
belongs_to 'role' to step to the related Role object row.
The related Role object has a value of role (the third 'role' in the TT
string), and this is the value that you want printed out.


[% END %]

I hope this helps. I'm learning too. I've taken a lot from this list, and
I'm trying to give back.


-Tim


On Wed, Jul 11, 2012 at 1:25 PM, Robyn Jonahs <learn.catalyst [at] gmail>wrote:

> Thanks Tim,
>
> I thought that the many_to_many was a relationship bridge and as limited
> to what it could do. I was studying the many_to_Many examples in the book
> to help my real problem in a test application I am trying to work on. I
> guess I should start a new thread for questions related to that. I will do
> that and try to continue understanding the relationships.
>
> Thanks
> RJ
>
> On Wed, Jul 11, 2012 at 12:48 PM, Tim Anderson <tja824 [at] gmail> wrote:
>
>>
>> <li>[% role.role.role %]</li> works because you're accessing the role
>> name (the third 'role') through the 'role' accessor (the second 'role')
>> which is defined in your many-to-many relationship:
>>
>> __PACKAGE__->many_to_many("roles", "user_roles", *"role"*);
>>
>> This is one of the beauties of DBIC; as soon as you have your
>> relationships defined, you have paths to the data you need. Imagine trying
>> to write the same type of request across a multiple key relationship.
>>
>>
>> -Tim
>>
>>
>> On Wed, Jul 11, 2012 at 11:29 AM, Robyn Jonahs <learn.catalyst [at] gmail>wrote:
>>
>>> Thanks, that worked. Now I am off to see why.
>>>
>>> [ snip ]
>>>
>>
>> _______________________________________________
>> List: Catalyst [at] lists
>> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
>> Searchable archive:
>> http://www.mail-archive.com/catalyst [at] lists/
>> Dev site: http://dev.catalyst.perl.org/
>>
>>
>
> _______________________________________________
> List: Catalyst [at] lists
> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
> Searchable archive:
> http://www.mail-archive.com/catalyst [at] lists/
> Dev site: http://dev.catalyst.perl.org/
>
>

Catalyst users RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.