Mastodon

Dealing with a stale cache at the Rails console

Working on other peoples apps can be tough. In spite of all the “convention” that is supposed to come over configuration, people still do a hell of a lot of configuring. In the end it takes a while figure out what’s what in a new app. Different places to create the same effect, dozens of ways to write equivalent code. After scratching my head for a while over a page that had a bunch of links to various models that all resulted in 404’s I was getting a little frustrated. The production log was no help. After dumping the DB and copying it to my dev database I noticed the problem was gone when I ran the app on my local machine. WTF? Then it hit me: Its cached.

So the task was to clean a stale cache from the console. A little searching turned up these gleaming bits of awesomeness and I’m putting them up here so I never forget them. For a starter on caching you should definitely check out the Railsguide.

This will return the cache directory in case you need to “expire” it manually (defaults to the public directory):

ActionController::Base.page_cache_directory

Or clear a page from the cache with something like this:

ApplicationController.expire_page(:controller => “site”, :action => “index”)

or a fragment:

ActionController::Base.new.expire_fragment(:controller => “my”, :action => “index”)
ActionController::Base.new.expire_fragment(/\/productions.*/)
ActionController::Base.new.expire_fragment(‘sidebar’)

I’ll be remembering that one!

Rails 3 on Heroku

Heroku sent around an email a little while ago talking about their “experimental” Rails 3 support. After a night of tinkering with a Rails 3 project  I thought I might try it out. When I pushed my project I got this:

Total 131 (delta 27), reused 0 (delta 0)

—–> Heroku receiving push
—–> Gemfile detected, running Bundler
Unresolved dependencies detected; Installing…
Fetching source index from http://gemcutter.org/
Resolving dependencies
Installing abstract (1.0.0) from system gems
Installing actionmailer (3.0.0.beta) from rubygems repository at http://gemcutter.org/
Installing actionpack (3.0.0.beta) from rubygems repository at http://gemcutter.org/
Installing activemodel (3.0.0.beta) from rubygems repository at http://gemcutter.org/
Installing activerecord (3.0.0.beta) from rubygems repository at http://gemcutter.org/
Installing activeresource (3.0.0.beta) from rubygems repository at http://gemcutter.org/
Installing activesupport (3.0.0.beta) from rubygems repository at http://gemcutter.org/
Installing arel (0.2.1) from rubygems repository at http://gemcutter.org/
Installing builder (2.1.2) from system gems
Installing bundler (0.9.12) from rubygems repository at http://gemcutter.org/ /usr/local/lib/ruby/site_ruby/

1.8/rubygems/installer.rb:192:in `install’: bundler requires RubyGems version >= 1.3.6 (Gem::InstallError)
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/source.rb:42:in `install’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/installer.rb:30:in `run’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/installer.rb:18:in `each’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/installer.rb:18:in `run’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/installer.rb:6:in `install’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/cli.rb:60:in `install’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor/task.rb:33:in `send’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor/task.rb:33:in `run’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor/invocation.rb:109:in `invoke’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor/invocation.rb:116:in `call’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor/invocation.rb:116:in `invoke’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor.rb:137:in `start’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor/base.rb:378:in `start’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor.rb:124:in `start’
from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/bin/bundle:11
from /usr/local/bin/bundle:19:in `load’
from /usr/local/bin/bundle:19
FAILED: Have you updated to use a 0.9 Gemfile?

Wha? I had filled out my Gemfile, what could it be? It turns out that you need to specify a “stack” to use when you are running Rails 3. The stack is basically all the a specific configuration of all the supporting software (the OS, Ruby, whatever else). Whatever stack I had been given by default (“aspen”) was not the one that contained Rubygems 1.3.6. Check out their stacks page on the Heroku site for more info.

The fix? Even Though I find Heroku’s documentation is usually pretty bad, this time they had exactly what I needed:

mike@sleepycat:~/projects/myapp$ heroku stack:migrate bamboo-ree-1.8.7
—–> Preparing to migrate
aspen-mri-1.8.6 -> bamboo-ree-1.8.7

NOTE: You must specify ALL gems (including Rails) in manifest

Please read the migration guide:
http://docs.heroku.com/bamboo

—–> Migration prepared.
Run ‘git push heroku master’ to execute migration.
Next time I pushed it worked fine. Yay!

Rails 3 finder syntax

Reading about Rails 3 and all the changes that were made is definitely exciting. Big changes to the ActiveRecord API, revamping routing, a tonne of new stuff. At the same time it felt kind of depressing because at first glance it all looked SO different. Even good changes mean that you have to remember the old stuff to work on your old apps and the new stuff for the new apps. Its not as though there isn’t enough learning involved in this occupation already…

Now that I am starting to play with Rails 3 in some of my personal projects, I am happy to report that there is plenty that is exactly the same in Rails 3 and that even the changes are pretty easy to get used to.

So here you go, some things are the same in Rails 3:

Model.find id

Model.find id, id

Model.all

Model.first

Model.last

Model.find_by_…..

Just avoid Model.find :first and Model.find :all. Especially since this syntax will not just deprecated but removed in Rails 3.2. Pratik from the core team has all the details.

The real changes are really just in how you handle giving options and conditions to the find. In fact the new syntax is very jQuery-like, which you are probably using anyway. It becomes natural very quickly.

Things like:

Model.where “id > 1”

or

Model.order(“id desc”).limit 1

There is lots more info over at Rails guides. Not so bad really. Now to figure out what they have done with the Routing!

Mysql’s explain and indexes in ActiveRecord.

After doing some work on optimising a query in Rails app I am working on I got to thinking about how useful MySQL’s explain statement is. It happens to be really useful for figuring out what, if any, indexes are being used by a given select statement. So I decided to see what I could do about adding that functionality to Rails myself. Projects like this really give you a great tour through a lot of Rails internals, so I figured it would be good for me whether I could figure it out or not. After a little hacking I came up with a patch to ActiveRecord::Base.connection that runs an explain statement before every select. I wrapped it in an unless statement to make sure it does not run if the mode is production.

Explain (0.000000)    | select_type: SIMPLE | key_len: 263 | table: taggings | id: 1 | possible_keys: index_taggings_on_tag_id,index_taggings_on_taggable_id_and_taggable_type | type: ref | Extra: Using where | rows: 1 | ref: const,const | key: index_taggings_on_taggable_id_and_taggable_type
Tag Load (0.000910)   SELECT `tags`.* FROM `tags` INNER JOIN taggings ON tags.id = taggings.tag_id WHERE ((`taggings`.taggable_id = 5) AND (`taggings`.taggable_type = ‘Member’))

The “possible keys” portion is where it lists the indexes for that apply to that query. If there are none there and this is a query that runs a fair bit you probably want to think about adding an index. For me this is a great way to make indexes, or a lack thereof more visible to me during development because they are really easy to forget. So in the spirit of “If you want to truly understand something, try to change it”, here is my first bit of tinkering with ActiveRecord:

unless RAILS_ENV == ‘production’
module ActiveRecord
module ConnectionAdapters
class MysqlAdapter < AbstractAdapter

def select_with_explain(sql, name = nil)

explanation = execute_with_disable_logging(‘EXPLAIN ‘ + sql)

e = explanation.all_hashes.first
exp = e.collect{|k,v| ” | #{k}: #{v} “}.join

log(exp, ‘Explain’)

select_without_explain(sql, name)
end

def execute_with_disable_logging(sql, name = nil) #:nodoc:
#Run a query without logging
@connection.query(sql)
rescue ActiveRecord::StatementInvalid => exception
if exception.message.split(“:”).first =~ /Packets out of order/
raise ActiveRecord::StatementInvalid, “‘Packets out of order’ error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information.  If you’re on Windows, use the Instant Rails installer to get the updated mysql bindings.”
else
raise
end
end

alias_method_chain :select, :explain

end
end
end
end

There it is, quick and dirty. If it ends up being something that I, or other people find really useful I will look at cleaning it up, adding some tests and maybe making a gem out of it. In the mean time you can just paste it into a file in your initializers directory. Happy indexing!

Caveats: I have got this working with Rails 2.1 with MySQL. Its only intended for helping out a little during development, and I have no idea what might happen if you run it elsewhere. If you have some suggested improvements I would love to hear them.

Wrong side of the tracks: Rails on Ubuntu

Ever noticed that all the Ruby on Rails people seem to be “Mac people”? DHH and Ryan Bates (Rails casts), the guy from Peepcode all spring to mind. My boss and every other person that I have met that works in Rails, all do it on a Mac.

Well it might not have the sex appeal of the Mac, but Ubuntu is an amazing development platform and runs Ruby on Rails perfectly. My only real gripe with it, is that its a pain keeping up with their release cycle. Six months goes by really fast, and every time I install the latest version of Ubuntu,  I have to set up Rails again (I’m not one for upgrades, clean installs are the way to go).

Last time I decided that enough was enough. I wrote a setup script that installs everything needed for Rails development in one go.

I’ve used it a few times since then and its already saved me hours of setup time so I thought I would make it available.  So here you go world, even though this might be the slightly ghetto way to develop in Rails, it just got a little easier.

You can find it on github: http://github.com/sleepycat/wrong-side-of-the-tracks

Setting up terminal windows for Rails development

Even though Netbeans make things like the Rails development log and the database connections pretty easy to get to, I still have a pretty strong preference for the command line. When I am coding I almost always have a few terminal windows open and stretched nice and big; generally one for mysql, one for the Rails development log and often a third for the Rails console in case I want to experiment with the code I am writing.

The down side to this set up is just that; the set up. Every day I type in the same stuff… mysql -u root blah blah blah.

So last night, after an ill advised post dinner coffee, I set about scripting my morning Rails ritual and on the way learned a bunch about the terminal.

Gnome terminal is the proper name for the program that resides under Applications > Accessories > Terminal. A quick look at the man pages give a pretty nice set of options to play with but I found they required a bit of trial and error to get right.

Cut and paste the ones you want into custom launchers.

Launching Mysql and getting a prompt on a specified database:

gnome-terminal  -e “mysql -u root -ppassword -D myapp_development”

Thats no typo! There can’t be any space between the -p option above and the actual password!

Launching a window with the Rails development log (with a specified Rail environment):

gnome-terminal  –working-directory=/home/mike/projects/myapp -e “script/server -e mikes”

That one is great for me because I am rapidly becoming sick of typing in stuff for custom Rails environments. Now I don’t need to!

Those are pretty fun, but the ultimate in convenience for me would be to have a single tabbed terminal window with everything. So why not combine the two into a single command?

gnome-terminal –geometry=174×46+50+50 –tab-with-profile=Default –title=”Mysql” -e “mysql -u root -ppassword -D myapp_development” –tab-with-profile=Default –working-directory=/home/mike/projects/myapp –title=”Server” -e “script/server -e mikes” –tab-with-profile=Default –working-directory=/home/mike/projects/myapp –title=”Console” -e “script/console mikes”

This is a doozie but it means that my whole morning Rails set up ritual has been reduced to a single click on a launcher. Sweet!