[Dancer-users] Flash Message

damien krotkine dkrotkine at gmail.com
Fri Jan 28 17:47:53 CET 2011


Hi,

Just released version 0.306.

I have pushed forward a bit more the idea of using a closure. Now the
before_template hook registers one closure per flash hash values,
instead of one unique closure for the whole flash hashref.

That means that in a template you can manipulate flash (test if it
exists, etc), and things will be removed only when used.

Also, keys are isolated, so it does fix  Brian E. Lozier concern (from
his otheremail).

So accessing flash.warning won't remove flash.error, etc.


Here is the code I used (also on github ). Any comment warmly welcome !

register flash => sub ($;$) {
    my ($key, $value) = @_;
    my $flash = session $session_hash_key || {};
    @_ == 2 and $flash->{$key} = $value;
    @_ == 1 and $value = $persistence ? $flash->{$key} : delete $flash->{$key};
    session $session_hash_key, $flash;
    return $value;
};

before_template sub {
   shift->{$token_name} = {  map { my $key = $_; my $value;
                                   ( $key, sub { defined $value and
return $value;
                                                 my $flash = session
$session_hash_key || {};
                                                 $value = $persistence
? $flash->{$key} : delete $flash->{$key};
                                                 session
$session_hash_key, $flash;
                                                 return $value;
                                               } );
                                 } ( keys %{session $session_hash_key || {} })
                          };
};




On 28 January 2011 10:05, damien krotkine <dkrotkine at gmail.com> wrote:
> Hi,
>
> Thanks for your contribution !
>
> I was thinking of doing something along that line. I wasn't sure
> Template::Simple was supporting coderef, but it seems it is :
>
>        elsif (ref($value)) {
>            local $@;
>            eval { $value = $value->$e };
>            $value = "" if $@;
>        }
>
> So yes, I'll change the code, along with tests.
> Your trick with $flashes staying in the scope longer than the token
> leaves in the hash is clever
>
>
>
>
> On 28 January 2011 09:02, Flavio Poletti <polettix at gmail.com> wrote:
>> Hi,
>>    I thought a bit about it and I think that the current implementation is a
>> bit too limited (this seems also what brian thinks in the bug
>> report http://rt.cpan.org/Public/Bug/Display.html?id=65009 - at least from
>> what I understand).
>> The problem is that the flash message might have to be displayed in the next
>> request, which happens when redirections kick in. In this case, the flash
>> message should be set, kept in the session and removed only when it is
>> actually displayed; this should happen automatically, i.e. without playing
>> with the $persistent variable - which is global - or with further overhead
>> on the controller side.
>> Following brian's feedback, I tried to re-code the plugin with the following
>> criteria:
>> * the "flash" method only adds messages (and handles many of them for every
>> category - you might have more than one error in a page). I see no point in
>> removing messages while inside the controller;
>> * the message removal logic is shifted in the template via an anonymous sub.
>> If the sub is called then the flash cache is cleared, otherwise it remains
>> there. This should guarantee that the messages are not removed until they
>> get the chance to be displayed.
>> This is the core of the recoding - not tested but should suffice to give you
>> the idea:
>> register flash => sub {
>>     my ($key, $value) = @_;
>>     my $flash = session($session_hash_key);
>>     if (! $flash) { # initialise the container for flash messages
>>       $flash = {};
>>       session($session_hash_key, $flash);
>>     }
>>     push @{$flash->{$key}}, $value;
>>     return;
>> };
>> before_template sub {
>>    my $obj = shift;
>>    my $flashes;
>>    $obj->{$token_name} = sub {
>>       if (! $flashes) { # first call, get messages and clear
>>          $flashes = session($session_hash_key) || {};
>>          session($session_hash_key, {});
>>       }
>>       return $flashes;
>>    };
>>    return;
>> };
>>
>> IMHO there is no need for an "exists", in the template you can do like this:
>> <% IF flash.errors %>...<% END %>
>> The important thing to remember is that even checking for the presence of
>> something inside "flash" clears the messages, which is consistent with the
>> semantics that "they get cleared as soon as they have a chance to be
>> displayed". The $flashes variable guarantees that they survive at least
>> until the end of the request, i.e. you are able to call "flash" multiple
>> times while handling a request and always get all messages.
>> If you think that this makes sense, I can propose a pull request on GitHub
>> or you can make the changes directly.
>> Cheers,
>>    Flavio.
>>
>>
>> On Tue, Jan 11, 2011 at 5:48 PM, damien krotkine <dkrotkine at gmail.com>
>> wrote:
>>>
>>> I've re-implemented it to be more Rails-like, as sukria said.
>>>
>>> https://github.com/dams/Dancer-Plugin-FlashMessage
>>>
>>> and on CPAN, pending  mirrors refresh.
>>>
>>> The funny part of the story ? the effective code is only 30 lines
>>> long. Talking about Perl and Dancer expressiveness...
>>>
>>> dams.
>>>
>>> On 11 January 2011 14:40, Alexis Sukrieh <sukria at sukria.net> wrote:
>>> > Hi list!
>>> >
>>> > Le 11/01/2011 14:29, damien krotkine a écrit :
>>> >>
>>> >> Hi,
>>> >>
>>> >> following previous thread, I've done a first implementation of
>>> >> Dancer::Plugin::FlashMessage :
>>> >>
>>> >> https://github.com/dams/Dancer-Plugin-FlashMessage
>>> >
>>> > Great! Thanks a lot for your time dams, the myth is still alived!
>>> > (Dancer's
>>> > community)++
>>> >
>>> >
>>> >
>>> >> Some parts need to be improved, for instance :
>>> >>
>>> >> - it supports only one flash message
>>> >> - the keywords are not short enough.
>>> >>
>>> >> So I think I'll change the implementation so that the template token is
>>> >> simply called 'flash', and it'll be a hash, like in Rails. I'll also
>>> >> change the registered method so that it's just flash() instead of
>>> >> get_flash()
>>> >
>>> > I agree. I'd like to behave just like Rails' flash feature. The idea is
>>> > pretty straight forward:
>>> >
>>> > "flash" is an accessor to a particular session hash table whose values
>>> > can
>>> > only be accessed once. Nothing more complicated than that.
>>> >
>>> > So to conclude, IMO, flash should be a wrapper like the following:
>>> >
>>> >    sub flash {
>>> >        my ($key, $value) = @_;
>>> >        my $flash = session('_flash');
>>> >
>>> >        # write
>>> >        if (@_ == 2) {
>>> >             $flash->{$key} = $value;
>>> >             session('_flash' => $flash);
>>> >        }
>>> >
>>> >        # read (+ delete)
>>> >        else {
>>> >            my $value = $flash->{$key};
>>> >            delete $flash->{$key} if defined $value;
>>> >            session('_flash' => $flash);
>>> >        }
>>> >
>>> >        return $value;
>>> >    }
>>> >
>>> > This is it, I think. This allows for the following code in a Dancer app:
>>> >
>>> >
>>> >     get '/' => sub {
>>> >         flash welcome => "This is a welcome message, only shown once";
>>> >     }
>>> >
>>> > Then, as soon as the key 'welcome' is accesed via flash('welcome'), the
>>> > entry will be purged.
>>> >
>>> > This will be very helpful for authentication stuff in before filters,
>>> > error
>>> > messages, notifications, ....
>>> >
>>> >
>>> > Kudos to dams!
>>> >
>>> > (BTW I haven't read the code yet)
>>> >
>>> > --
>>> > Alexis Sukrieh
>>> > _______________________________________________
>>> > Dancer-users mailing list
>>> > Dancer-users at perldancer.org
>>> > http://www.backup-manager.org/cgi-bin/listinfo/dancer-users
>>> >
>>> _______________________________________________
>>> Dancer-users mailing list
>>> Dancer-users at perldancer.org
>>> http://www.backup-manager.org/cgi-bin/listinfo/dancer-users
>>
>>
>


More information about the Dancer-users mailing list