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

Robyn Jonahs learn.catalyst at gmail.com
Wed Jul 11 15:58:27 GMT 2012


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 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:
=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> "CASCADE=
" },
);

=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> "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;



=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;
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.scsys.co.uk/pipermail/dbix-class/attachments/20120711/ce5=
d4e36/attachment-0001.htm


More information about the DBIx-Class mailing list