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: [email protected]
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/[email protected]/
Dev site: http://dev.catalyst.perl.org/

Reply via email to