Forum: Ruby on Rails Caching for layout variables

08bbdb4705bfab08daa3a7d607573490?d=identicon&s=25 Tim Shaffer (Guest)
on 2010-12-07 21:51
(Received via mailing list)
To make a long question short: I'm fairly new to caching in Rails.
What's the best way to cache stuff that is used in the layout without
caching the entire action/view?

Lets say I have the following in my Application controller to set some
variables that are used in my layout:

  before_filter :get_sidebar_items

  def get_sidebar_items
    @menu_items = MenuItem.all
    @archives = Post.all_grouped_by_month
  end

I can easily cache the display of the menu items in
application.html.erb using a fragment:

<% cache(:menu_items) do %>
  <% for i in @menu_items %>
    <%= i.name %>
  <% end %>
<% end %>

Problem is, that doesn't cache the database query. Is there a nifty
way to cache some global stuff like this? As far as I can tell, the
Caching Guide doesn't touch on this much.
Dd2d775dea75b381edb1bbf0600a0907?d=identicon&s=25 Marnen Laibow-Koser (marnen)
on 2010-12-07 22:12
Tim Shaffer wrote in post #967005:
> To make a long question short: I'm fairly new to caching in Rails.
> What's the best way to cache stuff that is used in the layout without
> caching the entire action/view?
>
> Lets say I have the following in my Application controller to set some
> variables that are used in my layout:
>
>   before_filter :get_sidebar_items
>
>   def get_sidebar_items
>     @menu_items = MenuItem.all
>     @archives = Post.all_grouped_by_month
>   end
>
> I can easily cache the display of the menu items in
> application.html.erb using a fragment:
>
> <% cache(:menu_items) do %>
>   <% for i in @menu_items %>
>     <%= i.name %>
>   <% end %>
> <% end %>
>
> Problem is, that doesn't cache the database query. Is there a nifty
> way to cache some global stuff like this? As far as I can tell, the
> Caching Guide doesn't touch on this much.

Look up the RDoc for ActiveSupport::Cache::Store.  You'll need to use
the interface described there (at least in Rails 2).

Best,
--
Marnen Laibow-Koser
http://www.marnen.org
marnen@marnen.org
08bbdb4705bfab08daa3a7d607573490?d=identicon&s=25 Tim Shaffer (Guest)
on 2010-12-08 16:40
(Received via mailing list)
On Dec 7, 4:12pm, Marnen Laibow-Koser <li...@ruby-forum.com> wrote:
> Look up the RDoc for ActiveSupport::Cache::Store. You'll need to use
> the interface described there (at least in Rails 2).

Thanks. Turned out to be way simple...

@menu_items = Rails.cache.fetch(:menu_items_all) { MenuItem.all }

And it's just as easy to delete it...

Rails.cache.delete(:menu_items_all)
81b61875e41eaa58887543635d556fca?d=identicon&s=25 Frederick Cheung (Guest)
on 2010-12-08 17:10
(Received via mailing list)
On Dec 8, 3:39pm, Tim Shaffer <timshaf...@me.com> wrote:
> On Dec 7, 4:12pm, Marnen Laibow-Koser <li...@ruby-forum.com> wrote:
>
> > Look up the RDoc for ActiveSupport::Cache::Store. You'll need to use
> > the interface described there (at least in Rails 2).
>
> Thanks. Turned out to be way simple...
>
> @menu_items = Rails.cache.fetch(:menu_items_all) { MenuItem.all }
>
Although this is sort of wasteful if you're also fragment caching in
the view (wasteful in that you put data in the cache that you don't
use, and wasteful of one roundtrip to your memcache).
There isn't really a great way to say in rails "this code here only
exists to support this fragment in the view, so don't bother executing
it if you're just going to display the fragment from the cache
anyway".
In some cases wrapping the database access up in a helper can work,
but calling models straight from your helpers isn't particularly nice.
Another solution is the interlock plugin
http://blog.evanweaver.com/files/doc/fauna/interlo...
although I haven't used that myself

Fred
Dd2d775dea75b381edb1bbf0600a0907?d=identicon&s=25 Marnen Laibow-Koser (marnen)
on 2010-12-08 18:23
Frederick Cheung wrote in post #967208:
> On Dec 8, 3:39pm, Tim Shaffer <timshaf...@me.com> wrote:
>> On Dec 7, 4:12pm, Marnen Laibow-Koser <li...@ruby-forum.com> wrote:
>>
>> > Look up the RDoc for ActiveSupport::Cache::Store. You'll need to use
>> > the interface described there (at least in Rails 2).
>>
>> Thanks. Turned out to be way simple...
>>
>> @menu_items = Rails.cache.fetch(:menu_items_all) { MenuItem.all }
>>
> Although this is sort of wasteful if you're also fragment caching in
> the view (wasteful in that you put data in the cache that you don't
> use, and wasteful of one roundtrip to your memcache).

But Memcached round trips are pretty cheap, since everything is in
memory.

> There isn't really a great way to say in rails "this code here only
> exists to support this fragment in the view, so don't bother executing
> it if you're just going to display the fragment from the cache
> anyway".
> In some cases wrapping the database access up in a helper can work,
> but calling models straight from your helpers isn't particularly nice.

I think DB access in a helper breaks MVC in most cases, because the
helper is really part of the view layer.

Concerns like this are contributing to a growing feeling on my part that
Rails-style MVC may be a mistake for certain types of complex Web
applications.  The question is whether something better exists... :)

Note also that I am *not* advocating breaking MVC while using Rails.

> Another solution is the interlock plugin
> http://blog.evanweaver.com/files/doc/fauna/interlo...
> although I haven't used that myself

Nor have I.  The Cells gem (which I also haven't used) might be useful
too.

>
> Fred

Best,
--
Marnen Laibow-Koser
http://www.marnen.org
marnen@marnen.org
08bbdb4705bfab08daa3a7d607573490?d=identicon&s=25 Tim Shaffer (Guest)
on 2010-12-08 19:52
(Received via mailing list)
On Dec 8, 11:08am, Frederick Cheung <frederick.che...@gmail.com>
wrote:
> the view (wasteful in that you put data in the cache that you don't
> use, and wasteful of one roundtrip to your memcache).

Agreed. I actually took the fragment cache out when I implemented the
Rails.cache.fetch bit.

The database roundtrip/query/parse is definitely more intensive than
just looping through the results in the view.
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.