Internationalization in edge Rails and more

There won’t be a Living on the Edge this week, but you won’t be starved for info because the Rails community is keeping up.

Ryan Daigle has been keeping up with some of the changes on edge Rails and has done a few awesome explanatory posts on them:

Perhaps even more noteworthy is the introduction of I18n (internationalization) support to Rails core. Sven Fuchs explains the technical details and API as well as the history of Rails and I18n. I18n support is scheduled to be fully stable in the Rails 2.2 release. Have an interest in internationalization in Rails? Lend a hand with your ideas, feedback, and patches at the Google Group.

Posted in Edge  | 7 comments

Living on the Edge (or what's new in Edge Rails) #3

There hasn’t been much of note in terms of big changes or features in edge Rails lately, so this time I’ll leave you to pore over the Rails commit logs for any bug fixes or minor changes that I haven’t pointed out. There has been some work in progress with ActionPack refactoring and multithreading work as well as some activity in ActiveModel too, but nothing really concrete yet (still very much a work in progress).

As usual, be sure to leave any suggestions and criticisms in the comments.

Thin support with script/server

script/server now checks for the availability of Thin and uses it. Pretty convenient if you are using Thin as your production server (and want to run the same when developing). You’ll have to add config.gem 'thin' to your environment.rb first to get this to work.

This patch was contributed by one of the guys at fluxin.

Changeset

String#humanize can be customized via inflection rules

The String#humanize core extension method is used convert strings with underscore, usually table column names, in them to pretty readable text. For example,

"actor_salary".humanize
=> "Actor salary" 
"anime_id".humanize
=> "Anime"

Sometimes this doesn’t work out so well though, when you have legacy tables or simply “inhumanely” named column names like “act_sal_money” (which is really “Actor salary”, but would be #humanize-d to “Act Sal Money”).

You can now specify custom inflection rules (just like you would for plural/singular/irregular/uncountable inflection rules):

Inflector.inflections do |inflect|
  inflect.human /_cnt$/, '\1_count'
  inflect.human 'act_sal_money', 'Actor Salary'
end

Notice how you can also use a regular expression above to convert columns like “click_cnt” to “Click count”.

Thumbs up to Dan Manges and Pascal Ehlert for this patch.

Changeset

Allow conditions on multiple tables to be specified using hash.

Pratik has committed a tiny (but really useful) change to ActiveRecord that allows you to specify conditions on a joined table in its own hash. An example would explain it better:

Anime.all(
  :joins => :character,
  :conditions => {
    :active => true,
    :characters => { :gender => 'female' }
  }
)

The ActiveRecord query above would find all “active” anime with “female” characters.

Changeset

Outro

That’s it for this week’s Living on the Edge – do let me know if you like to see more write-ups on even the minor bug fixes and changes that’d I’d left out this week.

Posted in Edge  | 10 comments

Living on the Edge (or what's new in Edge Rails) #2 - Performance improvements

The first Living on the Edge covered some of the API changes since Rails 2.1, and this time round, I’m going to cover the performance improvements as promised.

Jumping right in…

Faster Erb templates

Jeremy Kemper has made the Erb processing more efficient, especially the concat and capture helper methods.

The “special” Erb _erbout has been replaced with an instance variable, which allows for:
  • better (memory) performance because bindings are no longer being passed around,
  • fewer evals which are usually expensive,
  • there’s no need to slice the _erbout variable when you can swap in a new (string) buffer, and
  • the buffer is actually available via a output_buffer reader and writer methods (so you can override it if you want).

Relevant changesets: 933697a - 0bdb7d3 - 4d4c8e2

Faster partials and JavaScript helpers

Partial template initialization and JavaScript helpers have been refactored and optimized for speed and efficiency by Jeremy Kemper. These are but a few of the optimizations Jeremy has been committing recently. Be sure to check out some of the commits to Rails (or for that matter, any quality Open Source project) – you could learn something!

Relevant changesets: partialsJavaScript helpers

RecordIdentifier methods speedup

The RecordIdentifier has been sped up by some simple use of memo-ization, thus reducing the number of inflections performed, among other things. The RecordIdentifier is used widely in cache keys, partial template paths, and in most places where you identify an ActiveRecord model without caring about its actual id.

Relevant changesets by Jeremy Kemper: c1a9820566d717

Lazy load cache and session stores

Update: Oops my bad, this change was later reverted in 6573f6a.

The various cache stores in the ActiveSupport::Cache module are now lazy loaded – this means that they are only required when you actually start using them.

Changeset by Pratik Naik

Posted in Edge  | 8 comments

Living on the Edge (or what's new in Edge Rails) #1 - API changes and PerformanceTests

As Gregg Pollack mentioned a week or so ago, I’ll be keeping a weekly-or-so column about noteworthy changes on edge Rails. This is the first time Living on the Edge (of Rails) is appearing on the official Ruby on Rails weblog, so you’ll have to bear with my short introduction.

Living on the Edge is a weekly column I used to put up on my own blog after some prodding by Gregg Pollack of Rails Envy way back in December of 2007. I used to be a rather active Rails contributor back then so it was a no-brainer. Gregg and Jason were awesome enough to feature it weekly in their podcast.

And now it’s here, so try your best to be a tough crowd so I can tune these blog posts so that they are actually useful to you – when I was blogging these on my tiny personal blog it wasn’t that vital but now the audience is significantly larger. Leave your suggestions and criticisms in the comments – they are greatly appreciated!

Anyway, there’s been a ton of new features, API changes and performance improvements in the past 2 weeks or so since Rails 2.1 was released, so rather than dumping all into one mega-post, I’ve decided to break it into 2 posts for new features/API changes and performance improvements. In this post, I’m gonna talk about some of the new features and API changes.

Minor API changes

Let’s start jump straight in with some minor API changes.

link_to now takes a block

The link_to helper now takes a block argument for those occasions when you have really long hyperlink text with variables in them:

<% link_to(@profile) do %>
  <strong><%= @profile.name %></strong> -
  <span>Status: <%= @profile.status %></span>
<% end %>

Some people would find it cleaner than:

<%= link_to "<strong>#{@profile.name}</strong> -- <span>Status: #{@profile.status}</span>", @profile %>

Credit goes to Sam Stephenson (of Prototype fame) and DHH for this change.

Changeset details

ActiveRecord::Base#merge_conditions is now part of the public API

Jeremy Kemper has made ActiveRecord::Base#merge_conditions a public method.

This is pretty useful if you have conditions from multiple sources or like to combine any conditions for any reason.

Post.merge_conditions(
  {:title => 'Lucky ☆ Star'},
  ['rating IN (?)', 1..5]
)
=> "(`posts`.`title` = 'Lucky ☆ Star') AND (rating IN (1,2,3,4,5))"

Do note though that this merges with a SQL boolean AND only (no ORs).

Changeset details

Associations now take a :validate option

Association macros now accept a :validate option like so:

class Anime > ActiveRecord::Base
  has_many :characters, :validate => true
end

This tells ActiveRecord to validate the characters association when saving your Anime model – just like how :validates_associated works. The default is false, which is the current behavior in Rails 2.1 and earlier, so no need to fret. This works for all the other association macros as well (has_one, belongs_to, has_and_belongs_to_many).

Thumbs up to Jan De Poorter and Pratik Naik for this, which also fixes a nasty bug.

Changeset detailsTicket

ActiveSupport::StringInquirer and convenience Rails.env.development? methods

David Heinemeier Hansson (henceforth abbreviated as DHH – sorry!) recently added an ActiveSupport::StringInquirer String subclass that allows you to do this:

s = ActiveSupport::StringInquirer.new('awesome')
=> "awesome" 
s.awesome?
=> true
s.sucks?
=> false

An immediate use of this is when you are checking the environment your app is running in: Rails.env is wrapped in a StringInquirer so you can use query methods like Rails.env.development? and Rails.env.production?.

Changeset details

Core extensions: Object#present? and Enumerable#many?

DHH also added some core extensions that while trivial, could make your code more readable. First up is Object#present?, which is essentially !Object#blank?

[].present?
=> false
[1, 2].present?
=> true
"".present?
=> false
"i'm here".present?
=> true

An Enumerable#many? extension was also added that is simply a boolean test for enumerable.size > 1:

[].many?
=> false
[:just_me].many?
=> false
[:just_me, 'my_friend'].many?
=> true

Object#present? changesetEnumerable#many? changeset

Declarative block syntax for writing tests

DHH was inspired by Jay Fields when he committed this bit of syntatic sugar: you can now write your tests (Test::Unit) in declarative block style like so:

test "an anime should be invalid if any of its characters are invalid" do
  # Your usual test code here.
end

I seldom use Test::Unit (except when submitting Rails patches) and prefer RSpec – this declarative style of writing tests is definitely more readable.

All Rails-generated test stubs now use this new syntax.

Changeset details

Performance tests

Jeremy Kemper has been hard at work optimizing and improving the performance of Rails, so it’s no surprise that he has also introduced a new type of integration test: the performance test.

You can use the performance test generator (added by Pratik in 23232a) to generate a performance test stub.

script/generate performance_test LoginStories

Running the performance test requires ruby-prof >= 0.6.1, which is still unreleased but you can get at it the development version by checking out the source and installing the gem yourself (I suggest you get Jeremy’s fork of ruby-prof for now). It’s interesting to note that with the 0.6.1 release, ruby-prof supports profiling tests cases written using Test::Unit.

Moving on… Put in some test code (request a few controller actions – whatever user story you want to test performance of) and run the test. You’ll get output like this (together with the usual ruby-prof profiling output in the test/tmp/performance directory of your Rails app):

> ruby performance/login_stories_test.rb 
Loaded suite performance/login_stories_test
Started
LoginStoriesTest#test_homepage (32 ms warmup)
        process_time: 11 ms
              memory: unsupported
             objects: unsupported
.
Finished in 0.870842 seconds.

The memory and objects results are “unsupported” because I haven’t patched my Ruby interpreter for memory profiling support. You’d need certain Ruby interpreter patches to enable memory and GC profiling. I wish I could tell you more about how to do so, but I’m treading unfamiliar ground here. There are some details here on how to patch Ruby for memory profiling. I leave it for wiser folks to explain how to do this :)

Changeset details

Outro

That’s it so far for new feature/API changes in Rails since Rails 2.1 – performance improvements are coming up in the next post and I’ve also intentionally left out mention of the Rack support that has been partially merged into edge.

If there were any errors or you have any suggestions on how to make this column better, please point them out in the comments. Any info on patching your Ruby interpreter for memory profiling support is also greatly welcome. If I’ve left out anything that I’d considered not noteworthy enough but you disagree, let me know in the comments too.

Posted in Edge  | 14 comments

Rails premieres on GitHub

GitHub has now officially launched and Rails is right there at the premiere. The Rails repository now lives at rails/rails and you can check it out with:

git clone git://github.com/rails/rails.git

If you don’t have git, or don’t enjoy running it on your platform, you need not fear. We’ve set up an automated task to produce a zip file of Rails Edge that’ll be kept up to date all the time: http://dev.rubyonrails.org/archives/rails_edge.zip. This is also what we’ve made the new rake rails:freeze:edge use.

This also means that development on the Subversion repository has stopped and will no longer be kept up to date. We’ll keep the Subversion repository around for some time for people to transition off svn:externals, though. But if you want the latest edge, you’ll have to use either git or the new zip files.

We’ll also soon go live with our new ticket management system, which will be running on a new version of Lighthouse. When that happens, the Trac installation will follow the Subversion repository into legacy. We’ll still keep it around so we can work through all the patches and tickets that are there, but everything new will happen on the Lighthouse setup.

We hope you’ll enjoy this upgrade to the Rails collaboration infrastructure. We’re really looking forward to the onslaught of marvelous patches that the Git lords have promised us will flow from the mountain now.

Posted in Edge  | 41 comments