I am using fragment caching to render a select box where the contents
of the select box comes from a lengthy db query. A simplified example
showing the problem is
<% cache 'select_box' do %>
<%= f.collection_select :variety_id, @varieties, :id, :name %>
<% end %>
where @varieties is setup in the controller. Unfortunately this does
not achieve the desired result as the query is run even when the
select is picked up from the cache.
To get the full benefit I have to remove @varieties = Variety.all from
the controller and use
<% cache 'select_box' do %>
<%= f.collection_select :variety_id, Variety.all, :id, :name %>
<% end %>
but this breaks the rule that one should not access the model from the
view. Is there a good solution to this problem?
In the controller, you can check for the presence of the cached fragment using the read_fragment method. Then, only run the database query if the fragment isn't cached yet.
If you say in one breath "don't access models from the view" and then
in the next create a model class method... how's that different from
using the ".all" class method?
(btw I agree that one shouldn't access the model from the view - I'm
just querying that your suggestion may not remove this MVC-breaking
practice in this instance)
One take on this was interlock ( https://github.com/fauna/interlock )
although i haven't used it personally (and looks like it hasn't been
touched in a while)
I had noticed that some queries don't get run till the collection is
used, whereas others seem to run immediately. I did not find
documented exactly how to tell in advance which will get run and which
won't. I wonder whether using a named scope would guarantee delayed
operation.
OK, I provided a scope
scope :all_varieties
with no parameters.
Then in the controller
@varieties = Variety.all_varieties
and have confirmed that if the fragment is already cached so
@varieties is not used in the view, then the query is not run, so no
need test whether the fragment exists when setting up @varieties.
OK, I provided a scope
scope :all_varieties
with no parameters.
Then in the controller
@varieties = Variety.all_varieties
and have confirmed that if the fragment is already cached so
@varieties is not used in the view, then the query is not run, so no
need test whether the fragment exists when setting up @varieties.
This is the best solution I think.
Thanks again
Colin
Ack... obfuscated logic. If you are trying to not make the call when
the cache fragment already exists, then don't do so.
Don't squirrel it away behind a scope which does nothing except let you
defer the decision about executing the DB read and depend on a behavior
of AR which is determined when the view is being rendered...
Just a personal opinion. What works for you, works for you.
OK, I provided a scope
scope :all_varieties
with no parameters.
Then in the controller
@varieties = Variety.all_varieties
and have confirmed that if the fragment is already cached so
@varieties is not used in the view, then the query is not run, so no
need test whether the fragment exists when setting up @varieties.
This is the best solution I think.
Thanks again
Colin
Ack... obfuscated logic. If you are trying to not make the call when
the cache fragment already exists, then don't do so.
Sorry I am not sure what you are saying is best, are you suggesting I
*should* use fragment_exist? or I should not?