Archive for February, 2009
Selected Saturday Links
Feb 7th
Selected links that seem to deserve a bit more traction and longevity than a simple mention on twitter. Big themes this week were the release of Rails 2.3 RC 1 (which I explored through my work on the theme_support plugin and Clay Shirky’s series of talks in London. theme_support aside, I’ve mostly been focussed on some to-be-revealed developments to Generous and release an early version of the new Street Action site (DNS will hopefully propagate on that soon).
-
Interaction Design Pilot Year (Courses) » ToyView » Overview
“In this class, students created innovative ‘magical’ concepts, that are physical, serving as controllers and actuators for functions dealing with digital data. Digital data can be a wide set of elements, starting from pure text and ending in audio, videos, images, and at times even social particles. The emphasis was on creating a new hybrid of physical computer games.” – via @moleitau
-
PSFK’s Good Ideas Salon: What are the hot ideas in mobile?
Matt Jones: “We should be an embodied person in the world rather than a disembodied finger tickling a screen walking down the street. We need to unfold and unpack the screen into the world.” Lovely.
-
A Plugin Development Pattern » Learning jQuery
Some nice tips to bear in mind when building jQuery plugins.
-
Mashing up planning data with Google Maps
Some local government departments are using the PlanningAlerts.com service to populate their own websites! I’ve no idea if the scrapers I wrote a year or so ago for PlanningAlerts got any usage, but it’s good to see the site getting some use regardless. Just a shame the councils don’t have the data exposed cleanly even for their own internal use!
-
Ruby on Rails 2.3 Release Notes
They’ve packed a lot into quite a short release cycle
-
Ryan’s Scraps: What’s New in Edge Rails: Nested Object Forms
Another write up of the nested object forms functionality in Rails 2.3. Very nice to see a standardised solution to this, since almost every project seems to tackle it at some point
-
Engines in Rails 2.3
Some support for “Rails Engines”, plugins that look a bit like mini-apps, has been built into Rails 2.3 James Adam’s write up shows how this compares with his Engines plugin.
-
Fraser Speirs – On the Flickr support in iPhoto ‘09
Good write up, from an entirely biased but very thoughtful source. It sounds like Apple built Facebook integration into iPhoto and then tacked flickr on without much thought to how experienced users actually use flickr. Maybe they should hire Fraser to help them out with that?
-
TED 2009 Write ups
A series of writeups of this year’s TED talks. I’ve particularly enjoyed the updates from Erik Hersman
-
The Changing Role of Nonprofits
Amy Sample Ward’s reflections, driven by an interview she conducted with Clay Shirky while he was in London
-
How Twitter Was Born
An early history of the web app that now dominates so many of our lives.
Rails 2.3 and theme_support part 3: Layouts
Feb 3rd
In my ongoing efforts to bring my fork of theme_support in line with Rails 2.3 I’ve covered the core views and email, but when I left off earlier today layouts still weren’t working.
The key problem with overriding layouts is that the process of identifying them relies on some class methods on ActionController::Base (provided in the ActionController::Layout module). Roughly put we have:
- ActionController::Base#render calls ActionController::Base#pick_layout
- ActionController::Base#pick_layout checks to see if there’s a specific layout requested and calls ActionController::Base#active_layout
- ActionController::Base#active_layout checks whether there’s a candidate layout for this controller or action and makes sure the layout exists by calling ActionController::Base.find_layout
- ActionController::Base.find_layout (class method) is called which checks the view_paths to find the appropriate layout in there
The issue is that as a class method ActionController::Base.active_layout has no knowledge of the specific controller instance, or the request object it contains, and so it can’t access our logic to determine the current theme.
One option would be to patch a number of these methods to hand a controller instance around which could be queried for the theme, but that seems rather clunky.
Another option is to wrap the active_layout method so that it (as an instance method) checks whether there is a current theme and if so, adds that theme’s path to the class level view_paths, removing it again after that check:
class ActionController::Base alias_method :theme_support_active_layout, :active_layout def active_layout(passed_layout = nil) if current_theme theme_path = File.join(RAILS_ROOT, "themes", controller.current_theme, "views") if File.exists?(theme_path) and ! self.class.view_paths.include?(theme_path) self.class.view_paths.unshift(theme_path) result = theme_support_active_layout(passed_layout) self.class.view_paths.shift return result end end theme_support_active_layout(passed_layout) end end
And it works!
So that’s views, emails and now layouts all working with theme_support on Rails 2.3. As before, you can get the results in the branch on github:
http://github.com/jystewart/theme_support/tree/rails-2-3-support
Over the next couple of weeks I’m hoping to test my patches on other releases in the 2.x series, probably using a test app with specs or stories that will put it through its paces. Once that’s done I may turn my attention to the other corners of the plugin (that I don’t personally use) like the asset helper methods, but if anyone wants to contribute patches in the meantime I’d love to get them.
Rails 2.3 and theme_support part 2: ActionMailer
Feb 3rd
Stage 2 of fixing up theme_support for Rails 2.3 was making sure that ActionMailer picked up themed templates (for stage 1 information see here). That’s something I’d not quite cracked in the 2.2 version, so starting afresh with 2.3 forced me to spend the time to look through the full render path and figure out what was going on.
ActionMailer is a little more complicated than ActionView in that there are multiple routes of entry (ways of sending emails) and each email can have multiple templates associated with it to allow for multipart email. But at the core of it all is the ActionMailer::Base#create! method. This executes the specific method that populates the mailer variables (ie. the code you actually write in your mailers) and then uses Dir.glob to look for appropriate templates for this email:
Dir.glob("#{template_path}/#{@template}.*").each do |path| template = template_root["#{template_path}/#{File.basename(path)}"] # Skip unless template has a multipart format next unless template && template.multipart? @parts < < Part.new( :content_type => template.content_type, :disposition => "inline", :charset => charset, :body => render_message(template, @body) ) end
The initial patch provides a couple of ways to specify the theme for an email. I’m mainly using the approach of specifying self.current_theme within a mailer method. eg:
class UserMailer < ActionMailer::Base def activation(user) setup_email(user) self.current_theme = user.site.theme @subject += 'Your account has been activated!' @body[:url] = "http://www.catapultmagazine.com/" end end
With that in place the next step was to patch ActionMailer::Base#create! so that instead of just looking at the main template_path it looked first in the relevant theme folder and then in the main template folder. So the code above becomes:
tpaths = [] tpaths < < File.join(RAILS_ROOT, "themes", self.current_theme, "views", mailer_name) if self.current_theme tpaths << template_path tpaths.each do |tpath| Dir.glob("#{tpath}/#{@template}.*").each do |path| template = template_root["#{tpath}/#{File.basename(path)}"] # Skip unless template has a multipart format next unless template && template.multipart? @parts << Part.new( :content_type => template.content_type, :disposition => "inline", :charset => charset, :body => render_message(template, @body) ) end break if @parts.any? end
The keen-eyed among you will notice that this means you can't have, say, your HTML part themed and your plain text part in your main app/views folder. There would be ways around that, but this seemed the cleanest approach to take.
UPDATE (5pm): I've now got layouts working too. More on that over here.
Rails 2.3 and theme_support
Feb 2nd
A couple of months back, I realised that two of my projects (Generous and Catapult) could do with the help of the theme_support Rails plugin. Discovering that it didn’t play nicely with Rails 2.1, I created a fork on github and hacked at the _pick_template method to get it to do what I wanted. It turned out a few people were interested in having the plugin work with Rails 2.1, some of whom used more of the plugin’s featured than I need, and a few further forks emerged. I’ve been meaning to work through them and merge together the best bits, but the impending release of Rails 2.3 stopped me in my tracks.
I’m particularly keen to upgrade to 2.3 because Catapult generates a lot of routes and 2.3’s improved route handling should save us quite a bit of RAM and a number of cycles. So it was rather frustrating to find that yet again a new release of rails broke the plugin. Many hours later, working my way through the render path and trying to find the optimal solution, I’m not quite there, but it sort of works and seemed worth writing up:
It turns out that for most templates there’s a single point we can patch that will handle things. ActionView::Base#view_paths returns an instance of ActionView::PathSet which is an augmented Array that ActionView consults to find a template that matches its current requirements. By overriding that method we can check to see if a theme should be active and add that theme’s folder to the set of paths to be consulted.
module ActionView class Base alias_method :theme_support_old_view_paths, :view_paths def view_paths paths = theme_support_old_view_paths if controller and controller.current_theme theme_path = File.join(RAILS_ROOT, "themes", controller.current_theme, "views") if File.exists?(theme_path) and ! paths.include?(theme_path) paths.unshift(theme_path) end end paths end end end
The hitch is that this doesn’t work for layouts, which take a slightly different path. In my case, that’s not a huge deal, but it’s a major omission for other uses. I’ve also not yet tested the actionmailer handling.
You can track progress in a branch on GitHub. I’ll post here as I make more progress, but would welcome any contributions from the rest of the community.
UPDATE (10pm): I just checked in ActionMailer support. More on that tomorrow.
Rails 2.3 and Grand Rapids WiFi
Feb 2nd
I like to always have at least one project on the go that works as a testbed for a variety of new Rails techniques, tools and releases. For a long time that project was Grand Rapids WiFi, a site that lapsed into some neglect after I moved (a long way) away from the town it focussed on, but which I still officially maintain. It was where I first tried Rails 1.1 and 1.2, where I got to grips with various geo tools, and where I first generated RDF and Atom from a Rails app.
With this morning’s announcement that there’s a release candidate of Rails 2.3 out, I decided the time was ripe to dust off the GR WiFi code and move it from Rails 1.2.x to 2.3.0. It turned out to be a nice quick process, even allowing for the time it took to move it all onto github.
- Tidy up environment.rb to remove some deprecated features, and specify the new gem version
- Run rake rails:update to rename application.rb to application_controller.rb
- Remove quite a few defunct plugins that we didn’t need anyway
- Replace a couple of plugins with relevant calls to config.gem
- Rip out the use of components (what was I thinking?) and add a new model to help with sidebars
- Tidy up a few old paths
- Update my deploy script to get the code from git rather than svn
This site was where I really learned my way around rails’ test/unit-based testing framework and I’m sad to say that the tests now lie rather neglected. If time allows, I’ll kick them back into shape so they can be used to uncover any dark corners of the code that haven’t survived the transition, but for now I just wanted to get the site upgraded quickly and hopefully running a bit more efficiently.
For those who’d like to play with the code, it’s all public now over on github. I make no promises as to the quality of the code, but feel free to take it, use it, path it, etc. If you do end up using it for anything, please do let me know.