Question

In Catalyst I'm trying to forward to a private action to do some work. Here is the function definition:

sub get_form :Private :Args(1) {
  my ($self, $c, $type_id) = @_;
  #do stuff
}

I try to forward to it like so:

$c->forward('get_form',[$type_id]);

But it just gives me this error:

Couldn't forward to command "get_form": Invalid action or component.

However, if I change the action from :Private to :Local, then it works. Does anyone know why this is and how to fix it? Thanks!

Was it helpful?

Solution

You don't need rather can't use :Args(1) for private actions in Catalyst.

From cpan Catalyst Manual: You can pass new arguments to a forward action by adding them in an anonymous array. In the called method(or forwarded method), you would get arguments in $c->req->args.

sub hello : Global {
    my ( $self, $c ) = @_;
    $c->stash->{message} = 'Hello World!';
    $c->forward('check_message',[qw/test1/]);
}

sub check_message : Private {
    my ( $self, $c, $first_argument ) = @_;
    my $also_first_argument = $c->req->args->[0]; # now = 'test1'
    # do something...
}

You can also use stash $c->stash->{typeid}; instead. Then you can directly call the method using $c->forward('priv_method');.

Ex:

   sub hello : Global {
        my ( $self, $c ) = @_;
        $c->stash->{message} = 'Hello World!';
        $c->forward('check_message'); # $c is automatically included
    }

    sub check_message : Private {
        my ( $self, $c ) = @_;
        return unless $c->stash->{message};
        $c->forward('show_message');
    }

    sub show_message : Private {
        my ( $self, $c ) = @_;
        $c->res->body( $c->stash->{message} );
    }

OTHER TIPS

If I were to guess, it's because you are telling to match certain urls (:Args(1)), but :Private "will never match a URL". "Catalyst's :Private attribute is exclusive and doesn't work with other attributes". Try passing info via the context object instead.

You can also avoid forward() at all if you wish and just call the method if it's the same controller:

sub myaction : Global {
    my ( $self, $c ) = @_;
    $self->dosomething( $c, 'mystring' );
}

sub dosomething {
    my ( $self, $c, $argument ) = @_;
    $c->log->info( $argument );
}

Even though you have to pass $c around, this can often be an easier to read approach.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top