Rails page caching and flash messages
Asked Answered
B

7

10

I'm pretty sure I can page cache the vast majority of my site but the one thing preventing me from doing so is that my flash messages will not show, or they'll show at the wrong time.

One thing I'm considering is writing the flash message to a cookie, reading it and displaying it via javascript and clearing the cookie once the message has been displayed. Has anyone had any success doing this or are there better methods?

Thanks.

Breena answered 26/2, 2010 at 17:44 Comment(0)
N
2

One solution would be to cache the page, but include a javascript snippet that will make another small request just for the section you want to be dynamic. So the user will download the page fully, and then when javascript executes, it will pull down the dynamic page element.

I wrote a short blog post about this a while back. http://chase.ratchetsoftware.com/2008/12/rails-caching-dynamic-fragments/

Also, Greg Pollack of RailsEnvy did a screencast where he focuses on having dynamic data in cached pages. http://railslab.newrelic.com/2009/02/05/episode-5-advanced-page-caching

Hope this helps,

Chase Gray

Nealey answered 26/2, 2010 at 19:6 Comment(3)
I like this idea. Seems like it could be the ticket.Breena
I think it's worth noting that this won't realise the full benefit of page caching, because the Rails process will still be hit every time instead of not at all. I can't think of a better solution though.Oncoming
Fragment caching is better than serving a second HTTP request that only requests data which could be included in the first one. This strategy would double the number of HTTP requests you serve.Rainger
I
8

Cacheable flash do this:

in your application controller:

after_filter :write_flash_to_cookie


def write_flash_to_cookie
    cookie_flash = cookies['flash'] ? JSON.parse(cookies['flash']) : {}

    flash.each do |key, value|
        if cookie_flash[key.to_s].blank?
            cookie_flash[key.to_s] = value
        else
            cookie_flash[key.to_s] << "<br/>#{value}"
        end
     end

    cookies['flash'] = cookie_flash.to_json
    flash.clear
end

and then read "flash" cookie via Javascript and insert the message inside the HTML

Isaac answered 2/3, 2011 at 20:22 Comment(0)
F
4

I'm dealing with the same problem and I found cacheable-flash plugin that does exactly what KJF described in the question.

I think this is simpler and nicer solution than making excessive ajax calls.

Flint answered 22/5, 2010 at 8:29 Comment(1)
I think this is the best approach for Rails. Most of the other answers to this question suggest building your own, but the cacheable-flash gem already solves this and solves it well. Thanks Anton and Pivotal Labs.Deluca
N
2

One solution would be to cache the page, but include a javascript snippet that will make another small request just for the section you want to be dynamic. So the user will download the page fully, and then when javascript executes, it will pull down the dynamic page element.

I wrote a short blog post about this a while back. http://chase.ratchetsoftware.com/2008/12/rails-caching-dynamic-fragments/

Also, Greg Pollack of RailsEnvy did a screencast where he focuses on having dynamic data in cached pages. http://railslab.newrelic.com/2009/02/05/episode-5-advanced-page-caching

Hope this helps,

Chase Gray

Nealey answered 26/2, 2010 at 19:6 Comment(3)
I like this idea. Seems like it could be the ticket.Breena
I think it's worth noting that this won't realise the full benefit of page caching, because the Rails process will still be hit every time instead of not at all. I can't think of a better solution though.Oncoming
Fragment caching is better than serving a second HTTP request that only requests data which could be included in the first one. This strategy would double the number of HTTP requests you serve.Rainger
C
0

You don't have to cache entire page. Try fragment caching API

Caballero answered 26/2, 2010 at 18:16 Comment(2)
Maybe he wants to cache the entire page? Page caching gives the biggest performance boost.Oncoming
Yes, correct. I'm already fragment caching at the moment to get around the problem of the flash.Breena
G
0

Old question... but I got around this by including the flash message into my cache key.

caches_action :show, cache_path: proc { |c|
  most_recent_update_time = MyClass.order('updated_at DESC').limit(1).first.try(:updated_at).to_i
  { tag: most_recent_update_time.to_s + c.flash.collect{|x| x}.join }
}

If you have flash messages on your show action this will obviously break the cache often, but works well if you aren't doing a lot of messages.

Griggs answered 16/8, 2012 at 20:5 Comment(0)
J
0

Unobtrusive Flash puts flash message into cookie, and displays it via JavaScript. It provides vanilla and Bootstrap flavored JS display logics. It works in normal and ajax requests. It is also easy to hook into frameworks such as AngularJS.

Jaal answered 12/10, 2012 at 6:5 Comment(0)
R
-1

I don't use Rails but this is how I did it in Python using UUIDs:

# set flash messages like this
def flash(self, title, body):
  session['flash_messages'].append({
    'title': title,
    'body': body,
    'uuid': uuid().hex  # stores a UUID as a string
  })

...

self.flash('foo', 'bar')

Then in the base template I have this:

<script type="text/javascript">
  {% for m in session.flash_messages %}
    if(!Cookies.get('{{m.uuid}}')) {
      Notify('{{m.title}}', '{{m.body}}');
      Cookie.set('{{m.uuid}}', 'true', 86400); // key, value, expiry seconds
    }
  {% endfor %}
</script>

I'll break it down for the Pythonically-challenged:

  1. When you add a flash message, you create a unique ID and store it with that message.
  2. Before you display the message, you check to see if a cookie named with the message's unique ID has been set.
  3. If that cookie has not been set, flash the message and set the cookie. Expire the cookie in a day, or as brief as you think is wise.

Now if this page is pulled from cache, it will be okay. At step 2 the test for the cookie will pass because it has already been set, and the message will not be displayed.

Rainger answered 10/7, 2010 at 10:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.