Caching pages with query strings in padrino-cache - caching

I have Padrino caching working in my app, e.g.
get :blog, cache: true do
# do a blog listing
end
But when the listings are paginated with will-paginate, it can't tell the difference between /blog and /blog?page=2, and always renders the cached copy of /blog. Is there any way to get this to work so that it caches per URL not per route?

Some spelunking in the Padrino issues provides this answer, which seems to work:
get :blog, cache: Padrino.config.cache do
cache_key { request.path_info + '?' + params.slice('page').to_param }
#do blog listing
end
The structure of the Padrino documentation seems to have changed since then, so the PR at the end of that issue no longer seems to be in the current documentation.

Related

how to use Sinatra-cache?

I am developing sinatra web app and
I would like to cache in server-side with sinatra-cache gem.
http://www.rubydoc.info/gems/sinatra-cache/0.3.7/frames
I can install it and it worked.
But now it cache all method.
Next what I want to do is limit a specific method to cache.
For example,
get '/cache-me'
will be cached but
get '/nocache'
won't be cached.
How can I control this ?
And also once cached , I want to expire after specified time duration.
How can I do it ?
You have to disable cache by your self.
In your get methods, just add no-cache parameter :cache => false to erb or haml calls. E.g.:
# To turn off caching on certain pages:
get('/nocahce') {
haml(:view_name, :cache => false) # <- here
}
Take a look on documentation for more details. Have a nice day!

No route matches [GET] "/"...Sometimes

So I'm a bit of a Rails n00b, so I'll apologize if this is really simple. When I access my server from another computer, I get this message:
No route matches [GET] "/"
And if I try to go to my subpages (Well, currently I only have one), I get something along these lines:
Unknown action
The action 'index' could not be found for AwebpageController
But here's the catch: this only happens sometimes. The rest of the time, the standard RoR homepage loads, and going to wwww.mydomain.com/awebpage serves up the page fine.
My Routes.rb looks like this:
Wobsite::Application.routes.draw do
resources :awebpage
end
And awebpage_controller.rb looks like this:
class AwebpageController < ApplicationController
end
And yes, index.html.erb for Awebpage does exist. It's all so simple that I don't understand what's going wrong. Oh, and my webserver is Thin (Not sure if that matters). Thanks in advance for any help!
You might want to add this to the top of your routes file to set the default controller and page for your site (i.e. http://www.mysite.com/):
root :to => "AwebpageController#index"
To remove the default Ruby on Rails webpage you'll also want to delete the index.html file in your /public/ directory.
Also, although not required, in your controller you're missing the function definition for index.
class AwebpageController < ApplicationController
def index
end
end
Normally you'd do application logic and serve up a view in this function; however if you do nothing RoR automatically loads the view associated with the page (index.html.erb).
If after all this you're still having a problem perhaps explicitly add index to the AwebpageController in your routes file; perhaps rails is only mapping www.mysite.com/Awebpage/ to Awebpage/index and not www.mysite.com/Awebpage/index.

Best way to cache a response in Sinatra?

I'm building a simple app on the side using an API I made with Sinatra that returns some JSON. It's quite a bit of JSON, my app's API relies on a few hundred requests to other APIs.
I can probably cache the results for 5 days or so, no problem with the data at all. I'm just not 100% sure how to implement the caching. How would I go about doing that with Sinatra?
Personally, I prefer to use redis for this type of things over memcached. I have an app that I use redis in pretty extensively, using it in a similar way to what you described. If I make a call that is not cached, page load time is upwards of 5 seconds, with redis, the load time drops to around 0.3 seconds. You can set an expires time as well, which can be changed quite easily. I would do something like this to retrieve the data from the cache.
require 'redis'
get '/my_data/:id' do
redis = Redis.new
if redis[params[:id]]
send_file redis[params[:id]], :type => 'application/json'
end
end
Then when you wanted to save the data to the cache, perhaps something like this:
require 'redis'
redis = Redis.new
<make API calls here and build your JSON>
redis[id] = json
redis.expire(id, 3600*24*5)
get '/my_data/:id' do
# security check for file-based caching
raise "invalid id" if params[:id] =~ /[^a-z0-9]/i
cache_file = File.join("cache",params[:id])
if !File.exist?(cache_file) || (File.mtime(cache_file) < (Time.now - 3600*24*5))
data = do_my_few_hundred_internal_requests(params[:id])
File.open(cache_file,"w"){ |f| f << data }
end
send_file cache_file, :type => 'application/json'
end
Don't forget to mkdir cache.
alternatively you could use memcache-client, but it will require you to install memcached system-wide.

How to force Kaminari to always include page param?

Kaminari's URL generation omits the page param if it is generating the link back to the first page. However, the application is designed to select a random page if the page parameter is omitted. Kaminari's default behaviour, then, precludes paginating back to the first page in a reliable way.
I've resolved this issue, and will post my solution below a bit later, but I wanted to post this question for posterity, and I'm also pretty new to Rails, thus I'm not sure my solution is the best or most elegant, and I'm interested in improvements and refinements, if just for my own selfish edification!
The line of code in Kaminari that implements the behaviour we want to change is in lib/kaminari/helpers/tags.rb, in the method Kaminari::Helpers::Tag::page_url_for.
def page_url_for(page)
#template.url_for #template.params.merge(#param_name => (page <= 1 ? nil : page))
end
To override this behaviour, I created a file lib/kaminari/helpers/tag.rb, containing the following:
module Kaminari
module Helpers
class Tag
def page_url_for(page)
#template.url_for #template.params.merge(#param_name => (page < 1 ? nil : page))
end
end
end
end
I then patched in the file by adding the following line to config/initializers/extensions.rb:
require "lib/kaminari/helpers/tag.rb"
My apologies for any awkwardness with the Ruby/Rails terminology, I'm still fairly new to Ruby. Comments and criticisms are welcome.
UPDATE
The new version of the kaminari source will require this as the updated line:
#template.url_for #params.merge(#param_name => (page))
Otherwise you will lose other params passed into your pagination call.
For clairity sake here is the full output of the new code:
module Kaminari
module Helpers
class Tag
def page_url_for(page)
#template.url_for #params.merge(#param_name => (page))
end
end
end
end
You will still place this inside an initializers file as Daniel suggested.
As of today (July 2016), the Kaminari master branch includes a config option params_on_first_page, which is false by default.
Setting this config option to true will include page params for all pages, including page 1.
Note that the master branch isn't a stable release, so use with caution!
This is the answer for 2018 as am writing this :
Like it's stated in the kaminari github home page
Run this to create a config file for kaminari :
rails g kaminari:config
This will create a file kaminari_config.rb in your config/initializers folder
Uncomment the line : config.params_on_first_page = false and replace false by true :
config.params_on_first_page = true
Restart your server if necessary. That's it :)

Get absolute (base) url in sinatra

Right now, I do a
get '/' do
set :base_url, "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}"
# ...
haml :index
end
to be able to use options.base_url in the HAML index.haml.
But I am sure there is a far better, DRY, way of doing this. Yet I cannot see, nor find it. (I am new to Sinatra :))
Somehow, outside of get, I don't have request.env available, or so it seems. So putting it in an include did not work.
How do you get your base url?
You can get it using request.base_url too =D (take a look at rack/request.rb)
A couple things.
set is a class level method, which means you are modifying the whole app's state with each request
The above is a problem because potentially, the base url could be different on different requests eg http://foo.com and https://foo.com or if you have multiple domains pointed at the same app server using DNS
A better tactic might be to define a helper
helpers do
def base_url
#base_url ||= "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}"
end
end
If you need the base url outside of responding to queries(not in a get/post/put/delete block or a view), it would be better to set it manually somewhere.

Resources