Joomla Demo Camp
Arash Sanieyan and Rastin Mehr are putting on a Joomla Demo Camp.
Joomla is an open source Content Management System with a great community and lots of momentum. I’ll be there for sure, and I’m looking forward to getting a great jump-start in to learning about Joomla. I guess I’ll get a crash course in PHP at the same time.
It’s on Tuesday Feb 26th from 5:30 to 8:30 PM.
This is a free event, but you’ll still need to register.
For more info, and to register, see here.
Still room for two more!
There is still room for two more people at the Intermediate Ruby on Rails Workshop tomorrow.
You have until midnight to sign up, so get cracking!
Adding json responses to all of your controller actions
format.json { render :json => @bookmark } |
Now, the easiest way to do this would be to add JSON response to the scaffolding. The templates are in RAILS_ROOT/vendor/rails/lib/rails_generator/generators/components/scaffold/. Open up the controller.rb template and add in the JSON response shown above to the index, show, update and destroy methods and you’re done.
Unfortunately, I had already mostly developed the API when I realized that I had to add in the JSON responses (It’s not Gerald’s fault, he told me long ago). So, I decided to write a quick rake task to do the job for me. To use it, create a file called add_json.rake in RAILS_ROOT/lib/tasks and copy the following code in to it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
namespace :rails do desc "Adds a 'format.json ...' line for each 'format.xml ...' line in every controller" task :add_json => :get_controller_list do @controllers.each do |controller| new_lines = File.open(controller, 'r').readlines.collect do |line| if line =~ /^\s+format\.xml/ [line, line.gsub(/xml/, 'json')] else line end end.flatten file = File.open(controller, 'w') do |file| file.puts new_lines end end end task :get_controller_list => :environment do @controllers = Dir.glob(File.join(RAILS_ROOT, 'app', 'controllers', '*_controller.rb')) end end |
Call the task from RAILS_ROOT like this:
rake rails:add_json
The task opens up every controller, and every time it finds a line that starts with format.xml, it makes a copy of that line just below with every instance of ‘xml’ replaced with ‘json’. It’s pretty very brain-dead: it doesn’t check if the json response is already there, so don’t run it twice on the same project.
Facebook!?! I-Don't-Get-It - What's the Social Web and Why Facebook Matters
(This is cross-posted from Gerald Bauer’s Blog.)
I’m working on preparing more material and code covering the Social Web and Facebook for the upcoming Intermediate Ruby on Rails Workshop that we’re putting on January 25th at BCIT.
Here’s the outline what I will cover:
- What is the Social Web? What’s Facebook?
- Why does Facebook matter? Facebook Statistics and Numbers
- Facebook and Ruby on Rails
- What’s RFacebook? What’s Facebooker?
- Creating a Facebook application using inline frames (@iframe@s)
- Creating a Facebook application using FBML (Facebook Markup Language)
Interested? Learn more and sign-up today for the world’s 1st Ruby on Rails workshop covering the Social Web including Facebook.
Bonus: Want to see world-class award-winning Facebook applications in action? Join us for Vancouver’s 2nd Facebook Developer (& Designer) Garage and 1st in the new year at the Vancouver Film School Theatre hosting the Best of the West 2007 Facebook Awards on Monday following our workshop. RailsAdvance is a proud official sponsor of the social web event.
Last day for Early-Bird Prices
After today, the Intermediate Rails Workshop will cost $50 more, so go sign up!
What is the Semantic Web? What's Web 3.0? What are Microformats?
(This is cross-posted from Gerald Bauer’s Blog.)
I’m working on preparing the material and code covering the Semantic Web and Microformats for the Intermediate Ruby on Rails Workshop that we’re putting on January 25th at BCIT.
Here’s the outline what I will cover:
- What is the Semantic Web? What’s Web 3.0?
- What are Microformats? Why do Microformats matter?
- Microformats and Browser Plugins and JavaScript APIs
- Microformats and Ruby on Rails
- Creating RESTful web services using Microformats
- Adding semantics to your RESTful web pages (marking up people, events, locations and more using Microformats) and enabling Google Map listings, exporting contacts to your address book and more.
Interested? Learn more and sign-up today for the world’s 1st Ruby on Rails workshop covering the Semantic Web, Web 3.0 and Microformats.
Fun with Single Table Inheritance
(This is cross-posted with spatten design, so apologies if you’ve seen this twice.)
I’m working on the sample application for the Intermediate Ruby on Rails Workshop that we’re putting on in January. I had to remind myself of some of the foibles of Single Table Inheritance (STI). I thought others might find this useful, so here’s what I found.
The Set-up
I have two types of posts in the application I’m building: posts by people with an empty room looking for a roomie (RoomiePosts), and posts by people looking for a room (RoomPosts). They both share a lot of the same attributes, so it’s not very DRY to create two separate models.
This is where Single Table Inheritance comes in. STI is basically a way of subclassing a single model, creating subclasses that all use the same database table.
What I did is create a Post model and two subclasses: RoomiePost and RoomPost. Here’s how you do it.
Creating the Database Table
Here’s the migration for the posts database table. Note that this uses the new migrations syntax in Rails 2.0.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class CreatePosts < ActiveRecord::Migration def self.up create_table :posts do |t| t.integer :rent t.date :start_date, :expiry_date t.boolean :includes_utilities t.string :text, :type t.timestamps end end def self.down drop_table :posts end end |
Most of the columns are pretty straightforward. text will contain the text of the post. start_date and expiry_date will determine when the post will start and stop being shown on the site. rent and includes_utilities will only be used by the RoomiePost subclass, but still need to be created for all subclasses of the Post model.
The interesting column is type. This allows Rails to determine which subclass the row should be loaded in to. If you set type = "RoomiePost", then it’s a RoomiePost. If you set type = "RoomPost", then it’s a RoomPost.
Creating the Models
You need to create a Post, RoomiePost and RoomPost model. They look like this:
In/app/models/post.rb
1 2 3 |
class Post < ActiveRecord::Base end |
/app/models/roomie_post.rb
1 2 3 |
class RoomiePost < Post end |
/app/models/room_post.rb
1 2 3 |
class RoomPost < Post end |
Note that RoomiePost and RoomPost are both subclasses of the Post model. Here’s where you run in to a “gotcha”.
You have to create the models in separate files. If you don’t, Rails ignores the subclassed models.
For more information, and another workaround, see this blog post. The comment by Chris at the bottom gives the ‘create the models in separate files’ solution.
Okay, so now you have the models all set up. You can do things like
>> p = RoomiePost.create(:rent => 800, :includes_utilities => true, :text => "Great room in a shared house in the Commercial Drive area") |
And it will create a row in the posts table with type = "RoomiePost". If you have 5 RoomiePosts and 2 RoomPosts, then Posts.count will return 7.
1 2 3 4 5 6 |
>> RoomiePost.count => 5 >> RoomPost.count => 2 >> Post.count => 7 |
Adding behaviour to STI models
I want to be able to determine if a post is active by looking at the start and expiry dates, and to get a list of all active posts, roomie_posts and room_posts. I also want to have a different icon for each post type.
The Post.active_post? and Post::active_posts methods are straight-forward:
1 2 3 4 5 6 7 8 9 10 11 |
class Post < ActiveRecord::Base def is_active? (start_date .. expiry_date) === DateTime.now end def self.active_posts self.find(:all).select {|p| p.is_active? } end end |
The only tricky part is that I used self.find(:all) instead of Post.find(:all) in the Post::active_posts method. This makes sure that RoomiePost::active_posts only returns RoomiePosts and RoomPost::active_posts only returns RoomPosts.
Getting the icon to work took a little more figuring out. If I wanted to do this in straight-up Ruby, I’d do something like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#!/usr/bin/env ruby class Post ICON_PATH = "icons" def initialize @icon_name = 'base.gif' end def icon File.join(ICON_PATH, @icon_name) end end class RoomiePost < Post def initialize @icon_name = 'roomie.gif' end end class RoomPost < Post def initialize @icon_name = 'room.gif' end end |
Then I could do this
1 2 3 4 5 6 7 |
ruby $>irb -r subclass_test irb(main):001:0> Post.new.icon => "icons/base.gif" irb(main):002:0> RoomiePost.new.icon => "icons/roomie.gif" irb(main):003:0> RoomPost.new.icon => "icons/room.gif" |
This doesn’t quite work in the Rails version. Not to worry, you only have to make one simple change:
replace the initialize method with an after_initialize callback.
The final post.rb, roomie_post.rb and room_post.rb files look like this:
post.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Post < ActiveRecord::Base ICON_PATH = "/images/icons" def after_initialize @icon_name = 'base.gif' end def icon File.join(ICON_PATH, @icon_name) end def is_active? (start_date .. expiry_date) === DateTime.now end def self.active_posts self.find(:all).select {|p| p.is_active? } end end |
roomie_post.rb:
1 2 3 4 5 6 7 |
class RoomiePost < Post def after_initialize @icon_name = 'roomie.gif' end end |
room_post.rb:
1 2 3 4 5 6 7 |
class RoomPost < Post def after_initialize @icon_name = 'room.gif' end end |
One final note: because of the way the after_initialize callback works, you have to actually define an after_initialize method. You can’t do something like this:
1 2 3 4 5 6 7 8 9 10 |
class RoomiePost < Post after_initialize :set_icon_name private def set_icon_name @icon_name = 'roomie.gif' end end |
If you want to learn more about STI, and a whole slew of other info on Rails, sign up for the Intermediate Rails Workshop on January 25th, 2008 in Vancouver.
Early Bird rates are available until January 9th!
Intermediate Rails Workshop
Gerald and I are excited to announce our first workshop: intermediate Ruby on Rails.
| Date: | January 25th |
| Time: | 9:00 – 5:00 |
| Location: | BCIT, downtown campus, Vancouver |
We’ll be building a web application and service from the ground up and then using the service to drive a Facebook and mobile application.
On the way, you’ll learn about best practices for web service and application design using REST, advanced ActiveRecord associations, web services and building Facebook and mobile applications in Rails.
For more information, see the workshop’s page
