Ruby on Rails: Clear a cached page - ruby-on-rails

I have a RoR application (ruby v1.8.7; rails v2.3.5) that is caching a page in the development environment. This wouldn't be so much of an issue, but the cached page's a elements are incorrect.
I haven't made any changes to the development.rb file and I haven't knowingly added any caching commands to the controllers.
I've tried clearing the browser's (Firefox 3.5 on OSX) cookie and page caches for this site (localhost). I've also restarted Mongrel. Nothing seems to help.
What am I missing?

This line in development.rb ensures that caching is not happening.
config.action_controller.perform_caching = false
You can clear the Rails cache with
Rails.cache.clear
That said - I am not convinced this is a caching issue. Are you making changes to the page and not seeing them reflected? You aren't perhaps looking at the live version of that page? I have done that once (blush).
Update:
You can call that command from in the console.
Are you sure you are running the application in development?
The only alternative is that the page that you are trying to render isn't the page that is being rendered.
If you watch the server output you should be able to see the render command when the page is rendered similar to this:
Rendered shared_partials/_latest_featured_video (31.9ms)
Rendered shared_partials/_s_invite_friends (2.9ms)
Rendered layouts/_sidebar (2002.1ms)
Rendered layouts/_footer (2.8ms)
Rendered layouts/_busy_indicator (0.6ms)

rake tmp:cache:clear might be what you're looking for.

I was able to resolve this problem by cleaning my assets cache:
$ rake assets:clean

Check for a static version of your page in /public and delete it if it's there. When Rails 3.x caches pages, it leaves a static version in your public folder and loads that when users hit your site. This will remain even after you clear your cache.

More esoteric ways:
Rails.cache.delete_matched("*")
For Redis:
Redis.new.keys.each{ |key| Rails.cache.delete(key) }

If you're doing fragment caching, you can manually break the cache by updating your cache key, like so:
Version #1
<% cache ['cool_name_for_cache_key', 'v1'] do %>
Version #2
<% cache ['cool_name_for_cache_key', 'v2'] do %>
Or you can have the cache automatically reset based on the state of a non-static object, such as an ActiveRecord object, like so:
<% cache #user_object do %>
With this ^ method, any time the user object is updated, the cache will automatically be reset.

Related

Rails recyclable cache keys not working (still contains cache_version)

I have a Rails 5.2 app that's configured to use the new much touted feature of recyclable cache keys.
I can confirm the setting is enabled in the console:
Rails.application.config.active_record.cache_versioning
=> true
ActiveRecord::Base.cache_versioning
=> true
BlogPost.cache_versioning
=> true
With this setting, blog_post.cache_key now returns a stable string, because the cache_version is actually stored inside the cache entry (as this article details):
blog_post.cache_key
=> "blog_posts/10317"
blog_post.cache_version
=> "20190417193345000000"
But the problem is, even tough everything works as expected in the console, I can't seem to see this working watching the server logs, because it keeps generating cache_keys that contain the cache_version:
In my view:
<% cache(['blog_post_list_item_v2', blog_post, I18n.locale, browser.device.mobile?]) do %>
...
<% end %>
In the server logs:
Rendered blog/blog_posts/_blog_post_list_item.html.erb (2.5ms) [cache miss]
Read fragment views/blog/blog_posts/_blog_post_list_item:0bdff42a9193ea497e5ed4a9cc2f51e8/blog_post_list_item_v2/blog_posts/10317-20190417193345000000/pt-br/ (0.5ms)
As you see, the cache key should be .../blog_posts/10317/, but it actually contains the timestamp.
After debugging through the Rails code, I could confirm that the key was actually stable. What gets printed in the server log includes the version for debugging purposes only, but the key being stored on your cache doesn't actually contain the version.
The version is stored instead within the serialized object in the cache, which is an instance of ActiveSupport::Cache::Entry and contains an attr_reader :version. So, if you're like me, you'd assume that the cache (for instance, raw HTML) was stored directly in memcached, but it actually is stored in the value attribute of that ActiveSupport::Cache::Entry (which also has the version attribute if you have cache_versioning turned on), and that entire object is saved serialized into the cache.
If you want to confirm it yourself, you can check your own memcached realtime log. If you're on a mac, first stop it (I'm assuming it was installed with homebrew) with brew services stop memcached, start it on the foreground with verbose mode with memcached -vv and take a look at the keys requested by rails. After you finish your study, brew services start memcached will re-enable memcached as a daemon.
Also, if you are migrating from the old way (without recyclable cache keys), you should wipe your cache first with Rails.cache.clear in the console. Remember to do that in production as well.
If you want to understand more about how this works, a good read is https://dzone.com/articles/cache-invalidation-complexity-rails-52-and-dalli-c, but debugging through the rails code with binding.pry was what got things clear to me.
In a nutshell, it's a very brilliant implementation in my opinion, and the cache recycling just makes it so much better (the article quotes DHH saying that 'We went from only being able to keep 18 hours of caching to, I believe, 3 weeks. It was the single biggest performance boost that Basecamp 3 has ever seen.')

Rails.cache.clear returns nil

I have this setup
config.cache_store = :redis_store, ENV['REDIS_CACHE_URL']
$ redis-cli
127.0.0.1:6379> set random_key 1
OK
Now I go to the console and do Rails.cache.clear which returns nil
And I am still able to access the key random_key in the redis-cli. It did not clear the cache.
I could not read what Rails.cache returns here too ruby/2.3.4/lib/ruby/gems/2.3.0/gems/railties-4.2.8/lib/rails.rb
Is Rails.cache.clear is supposed to return true?
Can someone please help me out if my understanding is wrong?
redis-cache stores data under a particular namespace.
For example, if you've configured redis-store according to Documentation, then cache keys will be stored under cache namespace. That means, that when you Rails.cache.write("random_key", "key") a key cache:random_key will appear in the Redis. Therefore, when you Rails.cache.clear, only keys under cache namespace will be deleted.
Hence, if you manually create random_key in Redis, Rails.cache.clear won't remove it. But if you manually create cache:random_key, it will.
Be careful when using Rails.cache.clear it will invalidate all the keys for the application (source)
[~Not sure if this is the best place for this answer~]
This helpful article was a great way for me to understand caching when changing versions of Rails from 5.1+ to Rails 6.1+. The article talks about options for generating a cache key with or without versioning.
In the instance of my application, versioning was needed but not turned on when upgraded to Rails 6.1:
#in application.rb
config.active_record.collection_cache_versioning = true
Then within the application code where object.cache_key is called, I had to change it to object.cache_key_with_version (source)

Way to examine contents of Rails cache?

I'm trying to debug stale entries in a cached view in a Rails (5.0.0.beta2) running on Heroku. I'd like to look at the entries in the cache to confirm that they are named the way that I expect and are getting expired when they should.
Is there any way to do this? I found this question, HOW do i see content of rails cache, which suggests Rails.cache.read("your_key"). So, using bin/rails c (on Heroku) I tried:
Rails.cache.read(User.find(19).cache_key) => nil
Where 19 is the :id of one of the users for whom I'm seeing stale data. This has me kind of stumped...
If I try:
User.find(19).cache_key => "users/19-20160316151228266421"
But when a cache entry is supposedly expired the log line looks like:
Expire fragment views/users/19-20160316151228266421 (0.2ms)
So I tried doing a Rails.cache.read on that path, this also returned nil – I also tried doing the same with a user that had not be expired, and got nil again.
I'm wondering if that difference in path signals a problem, or if there is a way to see the path of the key that is created (I've been assuming that it matches at least the part after the slash).
Cache has the following instance variables:
[:#options, :#data, :#key_access, :#max_size, :#max_prune_time, :#cache_size, :#monitor, :#pruning]
You can examine the data with:
Rails.cache.instance_variable_get(:#data)

In Rails 3.1, how can I cache the results of a AR query to a cache?

For an AR query like this:
#users = User.find(some_conditions_here)
then #users is an AR array and I want to cache this.
If I do, in one controller call, a
Rails.cache.write('foo',#users)
it doesn't complain or error out and I can even see a 'foo' under /tmp/cache with a non-zero size but a subsequent controller call to
Rails.cache.read('foo')
returns a nil. When I do both the write and read from a Rails console, it works as expected. What is it about doing it via a controller that causes this problem?
This used to work before in Rails 2... what am I missing?
Check that config.action_controller.perform_caching is set to true.
To quote the Rails caching guide,
caching is disabled by default for development and test, and enabled for production

Rails.cache.read returns nil in rails, but not in console

I'm attempting to cache and read a user object via its api key. The use gets cached fine, and I can read the cache in the rails console, but for whatever reason doing the same exact Rails.cache.read in the rails app always returns nil.
Heres an example of what I'm doing. This is in a before_filter function.
def authKey
#?api=ce6f95a8bf7f9861330ede58f8972981
key = params[:api]
cu = Rails.cache.read(key)
#<do some logic>
logger.debug("CACHING USER #{key}")
Rails.cache.write(key, user)
The cu will always be nil, but the object will exist in memcache. Has anyone else run into this sort of problem? I'm using the dalli gem with compression enabled.
I believe that rails caching is off by default for development and on in test and production. Check in config/environments/development.rb and see what config.cache_classes is set to...
Caching is turned off by default for development environment.
Adding 'config.action_controller.perform_caching = true' to config/environments/development.rb should fix the problem.
http://guides.rubyonrails.org/caching_with_rails.html#basic-caching
In dev mode you can toggle caching by running rails dev:cache

Resources