FAQ
I've managed to keep context related items (e.g. current user) out of my
DBIC model up until now. Now finding it would be very helpful to be able to
call a method on a row object and have access to the current user.

So, I'm trying to hunt down an example of how to make a current user
available to row objects. Seems this has come up many times but not having
much Google luck.

Anyone have a link or an example?

Thanks,

--
Bill Moseley
moseley@hank.org
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100513/d2a16276/attachment.htm

Search Discussions

  • Kieren Diment at May 13, 2010 at 9:54 pm

    On 14/05/2010, at 7:37 AM, Bill Moseley wrote:

    I've managed to keep context related items (e.g. current user) out of my
    DBIC model up until now. Now finding it would be very helpful to be able to
    call a method on a row object and have access to the current user.

    So, I'm trying to hunt down an example of how to make a current user
    available to row objects. Seems this has come up many times but not having
    much Google luck.

    Anyone have a link or an example?

    Thanks,

    --
    Bill Moseley
    moseley@hank.org
    _______________________________________________

    From the book:

    =head2 Catalyst::Model::Factory and Catalyst::Model::Factory::PerRequest

    Thanks to Johnathan Rockway for assistance.

    We've used Catalyst::Model::Adaptor elsewhere in this book to set up a plain
    class as a Catalyst model at application startup time. This helps us to write
    Models that will work equally well outside of Catalyst as inside Catalyst. If
    you need more flexbility than this you should use
    Catalyst::Model::Factory::PerRequest to instantiate your class once per
    Catalyst request, or Catalyst::Model::Factory if you need a new object every
    time you call a particular C<<$c->model>>. Setup for either is the same as
    Catalyst::Model::Factory.

    Here's a simple Class that uses Catalyst::Model::Factory:

    package MyApp::Model::Something;
    use strict;
    use warnings;
    use parent 'Catalyst::Model::Adaptor';

    __PACKAGE__->config(
    class => 'Some::Plain::Class',
    args => { arg => $self->arg},
    );

    1;

    =begin comment

    JAR - It doesn't look like it uses Catalyst::Model::Factory. Is there a missing
    use line?

    =end comment

    Say we needed access to Catalyt's C<path_to> method in our Model. We could
    easily set this up within a Catalyst::Model::Adaptor model with the following
    inside our MyApp::Model::FromAdaptor class:

    use Moose;
    use namespace::autoclean;
    sub ACCEPT_CONTEXT {
    my ($self, $c ) = @_;
    my $new = $self->meta->clone_object($self, arg => $c->path_to(''));
    return $new;
    }

    However, if we needed information from the current Catalyst request object for
    our model to work, then we'd want to use C<use parent
    'Catalyst::Model::Factory' instead, and our ACCEPT_CONTEXT might look like
    this:

    =begin comment

    JAR - Where would we C<use parent qw(Catalyst::Model::Factory) instead?

    What is ACCEPT_CONTEXT? I don't remember seeing that before.

    =end comment

    =begin comment

    DWP - You've missed the closing > in the last para.

    =end comment

    use Moose;
    use namespace::autoclean;
    sub ACCEPT_CONTEXT {
    my ($self, $c ) = @_;
    my $new = $self->meta->clone_object($self, arg => $c->req->path);
    return $new;
    }

    =begin comment

    JAR - Is this example (above) still giving us access to Catalyst's C<path_to>
    method? Or would we not need that? I'm a bit confused.

    =end comment

    This is because models inheriting from Catalyst::Model::Factory are
    instantiated at run time, and so don't have access to the current request path.

    Finally if our model depended on something to do with the current application
    state, we'd want to C<use parent 'Catalyst:Model::Factory::PerRequest'> and our
    ACCEPT_CONTEXT subroutine might be as follows:

    use Moose;
    use namespace::autoclean;
    sub ACCEPT_CONTEXT {
    my ($self, $c ) = @_;
    my $new = $self->meta->clone_object($self, arg => $c->stash->{something});
    return $new;
    }
  • Bill Moseley at May 14, 2010 at 8:59 pm

    On Thu, May 13, 2010 at 2:54 PM, Kieren Diment wrote:

    sub ACCEPT_CONTEXT {
    my ($self, $c ) = @_;
    my $new = $self->meta->clone_object($self, arg =>
    $c->stash->{something});
    return $new;
    }
    Hum, I'm not clear how that works with Catalyst::Model::DBIC::Schema,
    because I want to be able to call "current_user" on any row object.
    $track->current_user.


    Again, I have some aversion to saving a current user in my model. That was
    more my question. Getting something to work is easy enough, just not sure
    it's the best approach.

    For example:

    In my Music::Schema base class I add an accessor:

    has 'current_user' => ( is => 'rw' );

    Then in my Result base class add a convenience method:

    sub current_user { return shift->result_source->schema->current_user }

    Now, I might want to have a method $track->can_user_access so in my Track
    class:

    sub can_user_access {
    my ( $track, $current_user ) = @_;

    # Use saved user if one not passed.
    $current_user ||= $track->current_user || die 'no current_user';
    ...
    return $has_access;


    Finally, in Catalyst my Model class would then look like:

    package MyApp::Model::Music;
    use Moose;
    extends 'Catalyst::Model::DBIC::Schema';
    use namespace::autoclean;

    before 'ACCEPT_CONTEXT' => sub {
    my ( $self, $c ) = @_;
    $self->schema->current_user( $c->current_user );

    };


    __PACKAGE__->meta->make_immutable;
    1;


    That implementation is simple enough, but not clear is it's the best
    approach.


    Backing up, the issue that came up is I have a base class used for setting
    up very common actions for an API. The controllers for, say,
    /music/track/$id are set up with configuration only:

    package MyApp::Controller::Music::Track;
    BEGIN { extends 'MyApp::Controller::API' }
    __PACKAGE__->config(
    return_colums => [qw/ id track_name position can_user_access /],
    );
    1;


    The controller base class then builds a response that includes those columns
    and methods. But, the base class doesn't know when to pass in the current
    user to a method (e.g. for can_user_access).

    So, I either extend the config to tell the base class to pass the current
    user to some methods:

    pass_user_to_meethod => [ 'can_user_access' ]


    Or I use something like ACCEPT_CONTEXT to set the current user in the
    schema.

    Better ideas?


    This is going to be a killer Music app. I just hope CDs don't go out of
    style.



    --
    Bill Moseley
    moseley@hank.org
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100514/fc1675f4/attachment.htm
  • Tomas Doran at May 21, 2010 at 4:46 pm

    On 14 May 2010, at 21:59, Bill Moseley wrote:
    Better ideas?
    DBIx::Class::Schema::RestrictWithObject ?

    Cheers
    t0m

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupcatalyst @
categoriescatalyst, perl
postedMay 13, '10 at 9:37p
activeMay 21, '10 at 4:46p
posts4
users3
websitecatalystframework.org
irc#catalyst

People

Translate

site design / logo © 2021 Grokbase