Beefy Boxes and Bandwidth Generously Provided by pair Networks DiBona
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Catalyst: stash vs. flash

by roho (Monsignor)
on Apr 26, 2010 at 01:21 UTC ( #836827=perlquestion: print w/ replies, xml ) Need Help??
roho has asked for the wisdom of the Perl Monks concerning the following question:

I am working through the example in Jonathan Rockway's Catalyst book on pp. 43-49 to add a search function to the AddressBook application. Running the sample code from the book (with mods to switch from FormBuilder to FormFu) displays search results, but leaves the wrong URL in the address bar.

Stash Example (see lines 28, 31, 33, 37)
1 package AddressBook::Controller::Search; 2 use strict; 3 use warnings; 4 use Text::CSV_XS; 5 use parent qw(Catalyst::Controller::HTML::FormFu); 6 7 sub search : Global FormConfig { 8 my ($self, $c, $query) = @_; 9 my $form = $c->stash->{form}; 10 11 # Get query from search form 12 if ($form->submitted_and_valid) { 13 $query = $c->request->param('query'); 14 } 15 return unless $query; # No query? We're done 16 $c->stash->{query} = $query; 17 18 # Parse query into tokens 19 my $csv = Text::CSV_XS->new(); 20 $csv->parse($query) or die "Error parsing query"; 21 my @tokens = $csv->fields(); 22 23 # Process query from search form and stash results 24 my $result; 25 if ($form->submitted_and_valid) { 26 if ($c->request->param('domain') eq 'Names') { 27 $result = $c->forward('search_names', \@tokens); 28 $c->stash->{template} = 'search/name_results.tt2'; 29 } else { 30 $result = $c->forward('search_addresses', \@tokens); 31 $c->stash->{template} = 'search/address_results.tt2'; 32 } 33 $c->stash->{result} = $result; 34 my $page = $c->request->param('page'); 35 $page = 1 if ($page !~ /^\d+$/); 36 my $page_result = $result->page($page); 37 $c->stash->{pager} = $page_result->pager; 38 } 39 } 40 41 sub search_names : Private { 42 my ($self, $c, @tokens) = @_; 43 my @people_fields = qw/firstname lastname/; 44 @people_fields = cross(\@people_fields, \@tokens); 45 return $c->model('AddressDB::People')->search(\@people_fields); 46 } 47 48 sub search_addresses : Private { 49 my ($self, $c, @tokens) = @_; 50 my @address_fields = qw/postal phone email location/; 51 @address_fields = cross(\@address_fields, \@tokens); 52 return $c->model('AddressDB::Addresses')->search(\@address_fiel +ds); 53 } 54 55 sub cross { 56 my $columns = shift || []; 57 my $tokens = shift || []; 58 map {s/%/\\%/g} @$tokens; 59 my @result; 60 foreach my $column (@$columns){ 61 push @result, (map +{$column => {-like => "%$_%"}}, @$token +s); 62 } 63 return @result; 64 } 65 66 1;

Previously (pp. 39-40) the book showed how to use sessions to leave the correct URL in the address bar by using redirect as follows:
  $c->response->redirect($c->uri_for('<URL path>'));

This worked fine for the "edit" and "delete" actions previously in the application, but is not working for "search".

I replaced $c->stash->{template} = '<template-name>' with $c->flash->{template} = '<template-name>' and $c->stash->{result} = $result with $c->flash->{result} = $result, and $c->stash->{pager} with $c->flash->{pager}, which generated the following error message from DBIx::Class:
   undef error - Can't call method "select" on an undefined value at: C;/Perl/site/lib/DBIx/Class/ResultSet.pm line 670

Flash Example (see lines 28, 31, 33, 37)
1 package AddressBook::Controller::Search; 2 use strict; 3 use warnings; 4 use Text::CSV_XS; 5 use parent qw(Catalyst::Controller::HTML::FormFu); 6 7 sub search : Global FormConfig { 8 my ($self, $c, $query) = @_; 9 my $form = $c->stash->{form}; 10 11 # Get query from search form 12 if ($form->submitted_and_valid) { 13 $query = $c->request->param('query'); 14 } 15 return unless $query; # No query? We're done 16 $c->stash->{query} = $query; 17 18 # Parse query into tokens 19 my $csv = Text::CSV_XS->new(); 20 $csv->parse($query) or die "Error parsing query"; 21 my @tokens = $csv->fields(); 22 23 # Process query from search form and flash results 24 my $result; 25 if ($form->submitted_and_valid) { 26 if ($c->request->param('domain') eq 'Names') { 27 $result = $c->forward('search_names', \@tokens); 28 $c->flash->{template} = 'search/name_results.tt2'; 29 } else { 30 $result = $c->forward('search_addresses', \@tokens); 31 $c->flash->{template} = 'search/address_results.tt2'; 32 } 33 $c->flash->{result} = $result; 34 my $page = $c->request->param('page'); 35 $page = 1 if ($page !~ /^\d+$/); 36 my $page_result = $result->page($page); 37 $c->flash->{pager} = $page_result->pager; 38 if ($c->request->param('domain') eq 'Names') { 39 $c->response->redirect($c->uri_for('name_results/')); 40 } else { 41 $c->response->redirect($c->uri_for('address_results/')) +; 42 } 43 } 44 } 45 46 sub search_names : Private { 47 my ($self, $c, @tokens) = @_; 48 my @people_fields = qw/firstname lastname/; 49 @people_fields = cross(\@people_fields, \@tokens); 50 return $c->model('AddressDB::People')->search(\@people_fields); 51 } 52 53 sub search_addresses : Private { 54 my ($self, $c, @tokens) = @_; 55 my @address_fields = qw/postal phone email location/; 56 @address_fields = cross(\@address_fields, \@tokens); 57 return $c->model('AddressDB::Addresses')->search(\@address_fiel +ds); 58 } 59 60 sub cross { 61 my $columns = shift || []; 62 my $tokens = shift || []; 63 map {s/%/\\%/g} @$tokens; 64 my @result; 65 foreach my $column (@$columns){ 66 push @result, (map +{$column => {-like => "%$_%"}}, @$token +s); 67 } 68 return @result; 69 } 70 71 1;

I changed flash back to stash for {result} and the DBIx::Class error goes away and the correct URL is displayed in the address bar on the search results page, however no search results are displayed.

It almost seems like a catch-22 situation, where stash is needed for {result} to make DBIx::Class work, but flash is needed for {result} to make $c->response->redirect... work.

I tried using BOTH stash and flash but got the same error I received when using flash only.

Any ideas on how this problem might be resolved?
TIA

"Its not how hard you work, its how much you get done."

Comment on Catalyst: stash vs. flash
Select or Download Code
Re: Catalyst: stash vs. flash
by ikegami (Pope) on Apr 26, 2010 at 05:03 UTC
    In the handler to which you redirect, get the stuff from the flash and put it in the stash. There's even something called flash_to_stash that can do that for you. I don't remember the details, so Google for it.
      I have flash_to_stash enabled. It is enabled in the main AddressBook.pm module as follows:
      __PACKAGE__->config( session => {dbic_class => 'AddressDB::Session', flash_to_stash => 1 });

      I cannot get the stuff from flash because when I store the search results in flash I get the DBIx::Class error.

      "Its not how hard you work, its how much you get done."

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://836827]
Approved by AnomalousMonk
Front-paged by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (4)
As of 2014-04-20 13:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (485 votes), past polls