Log home for sale in Redmond
Our home in Redmond, WA is for sale. I’ve put together a page with some info and photos here.
How do you clear cached actions in Rails?
Careful, this is a trick question!
The obvious thing is to call ‘expire_action’ to remove the cached entries for the specified action. However, the fragment cache path for an action includes the controller name, and the expire_action method is a method on the controller, so the only cached actions you can expire are ones on the current controller.
What this really means is that those of you with ‘Admin’ controllers have to pass the controller into the expire_action as part of the options hash. This is essentially the same as url_for(), because url_for() is the method used to build the fragment cache key.
Seems like this can be improved.
And an opportunity for my action_cache plugin to help out. More later.
Update: Changed some information, as I found how the action cache uses url_for.
Lighttpd proxy with X-Sendfile and action_cache
If you use lighttpd as a proxy server, instead of using the FastCGI bindings, then you’ll find that my action_cache code to use X-Sendfile doesn’t work. The switch I was using to enable this feature was set in the process environment when lighttpd started the Rails process. The process isn’t started by lighttpd in the proxy case, so a new switch was needed.
I added a Request variable called HTTP_X_ENABLE_X_SENDFILE to do this. Set this to ‘true’, and X-Sendfile will be enabled for proxy requests.
I think this will only work with the new proxy code in the 1.5.0 lighttpd that Jan is currently working on. It still seems a little buggy, as I can’t get any response to the client with my settings:
$SERVER["socket"] == ":2200" {
setenv.add-request-header = ( "X_ENABLE_X_SENDFILE" => "true" )
proxy-core.allow-x-sendfile = "enable"
proxy-core.balancer = "sqf"
proxy-core.protocol = "http"
proxy-core.backends = ( "127.0.0.1:4000", "127.0.0.1:4001" )
}I can't use Rails caching because...
One of the reasons a site can’t use page or action caching in Rails is because different types of users see different page contents for the same URL. For instance, logged in users may see user specific info on the page, whilst other users will see a generic page. Until now, that would mean that the page can’t be cached for anyone.
I’ve just updated my action_cache plugin to help work around some of these cases and allow caching for at least some of the requests.
You can now implement a method on your controller to tell the action cache whether the current request should be cached or not. With this, you can decide, for instance, to cache requests when the user is not logged in and not cache requests for logged in users.
Here’s what that code looks like:
class ApplicationController < ActionController::Base
...
def cache_action?(action_name)
!user_logged_in?
end
...
endInstall the update using the Rails plugin script: script/plugin install action_cache, take a look at the source code
Comcast DVR isn't quite so bad
This is a follow up to my previous post about the Comcast DVR
Lisa called Comcast to see what could be done about the crashing. It turns out that the Comcast customer service people can send an update to the device, but you must call in to get this. The device doesn’t update itself at a convenient time.
Now we have the software update. the thing hasn’t crashed in weeks. It is more unresponsive to user input, but the annoying crashing every hour or two is gone.
It would seem that having to call in to get updates is a process that can’t possibly be cost-effective for Comcast.
Oh well, back to the TV…
Rails action_cache plugin updated to use x-sendfile
I’ve just checked in an update to my Rails action_cache plugin. The main change is that now, under the right conditions, the plugin will serve up the cache content using the X-Sendfile header supported by lighttpd and other web servers.
To use the X-Sendfile functionality, three things need to be configured:
- X-Sendfile support enabled in the web server
- The environment variable ENABLE_X_SENDFILE must be set
- The Rails fragment cache store must be set to use the FileStore class
The internal format of the cache has been changed to support the X-Sendfile code. Now the cache entry is stored in two fragments, one for meta-data and headers, the other for the response body.
The README has more info on how to set this up.
Fun with Rails action cache
I had the opportunity to use my action_cache plugin code in a project today. While adding the code to the project, I realized I could do a little better at caching than I had thought when I wrote the code some time ago.
The pages I needed to cache have a different menu, based on whether the user is an admin or not. How can I make this work without resorting to AJAX or client side JavaScript tricks?
I handled this case by implementing a custom fragment_key method. Mine now looks something like this:
ActionController::Caching::Actions::ActionCacheFilter.fragment_key = Proc.new {|controller|
"AC/#{controller.request.host_with_port}/#{controller.user_is_admin? ? "admin" : "user"}/#{controller.params.sort.join('/').gsub(' ', '-')}"
}Now I have different output cached for admin and non-admin users.
The fragment key generation can include any data your actions depend on for different output. My project uses Matt’s Theme Support plugin and multiple sites can use the same theme, so I can actually change my fragment_key method to something like this:
ActionController::Caching::Actions::ActionCacheFilter.fragment_key = Proc.new {|controller|
"AC/#{controller.current_theme}/#{controller.user_is_admin? ? "admin" : "user"}/#{controller.params.sort.join('/').gsub(' ', '-')}"
}Even I didn’t realize quite how powerful this feature was.
If anyone is using the action_cache plugin, can you leave a comment so I know who you are! Thanks
How hard is it to make X-Sendfile work in Lighttpd?
Install the code, follow the documentation, start the server, send the header. How hard could it be? Well, in some versions, it’s quite easy, however, the version of lighttpd I started with wasn’t one of them!
From my recent experience, version 1.4.13 with FastCGI just doesn’t work. Empty content all round, and no errors reading the configuration to clue me in to errors.
The 1.5.0 version of the code works great with FastCGI with the same configuration that doesn’t work for 1.4.13. However, the new proxy-core code doesn’t forward requests to my Mongrel instances. Probably an issue with my configuration, so I’ll play with this some more.
The proxy c0de in the 1.4.x codebase doesn’t do X-Sendfile, so that option is out.
Since 1.5.0 isn’t released yet, I would think twice about using it in production sites. And I really want to use Mongrel for my Rails code.
In summary: 1.4.13 – FastCGI doesn’t work, mod_proxy isnt implemented 1.5.0 – FastCGI works, mod_proxy doesn’t work
Using X-Sendfile in Rails with lighttpd
As a followup to my post on using x-sendfile, I sent some email to Jan, owner of lighttpd. He clued me into the mod_setenv module that allows me to write this in my lighttpd.conf:
setenv.add-environment = (
"ENABLE_X_SENDFILE" => "true"
)as well as the allow-x-send-file property for FastCGI and soon to be proxy-core configuration.
Now my Rails source code can look like this:
if request.env["ENABLE_X_SENDFILE"] == "true"
response.headers["X-Sendfile"] = filename_to_send
else
response.body = read_file(filename_to_send)
endThe configuration to enable x-sendfile is duplicated, but at least it’s in a single .conf file.