4

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!

srchulo
  • 5,143
  • 4
  • 43
  • 72

3 Answers3

8

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} );
    }
5

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.

arthas
  • 139
  • 4
4

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.

ikegami
  • 367,544
  • 15
  • 269
  • 518