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 <[email protected]>wrote: > Thanks, that worked. Now I am off to see why. > > > > > On Wed, Jul 11, 2012 at 12:26 PM, fREW Schmidt <[email protected]> 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" <[email protected]> >> 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: [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/ >>> >>> >> _______________________________________________ >> 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/ >> >> >
_______________________________________________ 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/
