<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8427238914290520785</id><updated>2011-07-08T09:54:29.950-07:00</updated><category term='merb'/><category term='tips'/><category term='datamapper'/><category term='rails'/><title type='text'>Domain Specific</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://domainspecific.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8427238914290520785/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://domainspecific.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Doug</name><uri>http://www.blogger.com/profile/02033627970527658208</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>3</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8427238914290520785.post-8597637737797183833</id><published>2008-08-12T05:51:00.001-07:00</published><updated>2008-08-15T07:45:49.901-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='datamapper'/><category scheme='http://www.blogger.com/atom/ns#' term='merb'/><title type='text'>Sample Application Using Edge Merb and DataMapper</title><content type='html'>&lt;p&gt;Okay, now that you have &lt;a href="http://domainspecific.blogspot.com/2008/08/edge-merb-and-datamapper-on-leopard.html"&gt;edge Merb and DataMapper installed&lt;/a&gt;, let's create our first app. Pick a directory where you want to put your app, and try the following:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;$ merb-gen app sample&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You should see "Generating with app generator:" followed by a list of the new directories and files Merb added for you. Change into that directory:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;cd sample&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and edit the config/init.rb file. Uncomment the DataMapper ORM line:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;use_orm :datamapper&lt;br /&gt;&lt;pre&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and also add a dependencies on merb_helpers and merb-assets:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;# ==== Dependencies&lt;br /&gt;&lt;br /&gt;# These are some examples of how you might specify dependencies.&lt;br /&gt;# Dependency loading is delayed to a later Merb app&lt;br /&gt;# boot stage, but it may be important when&lt;br /&gt;# another part of your configuration relies on libraries specified&lt;br /&gt;# here.&lt;br /&gt;#&lt;br /&gt;dependencies "merb_helpers", "merb-assets"&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Finally, if you want to add query logging from DataMapper, add this to the 'after_app_loads' block:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;br /&gt;Merb::BootLoader.after_app_loads do&lt;br /&gt;&lt;br /&gt;  DataObjects::Mysql.logger = DataObjects::Logger.new('log/dm.log', 0)&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Now, let's set up our databases:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;$ rake dm:db:database_yaml&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Rename (or move) the generated config/database.yml.sample file to config/database.yml. Then go ahead and enter the correct values for the setup you want. Here's how I have mine: &lt;/p&gt;&lt;br /&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;br /&gt;development: &amp;amp;defaults&lt;br /&gt;# These are the settings for repository :default&lt;br /&gt;adapter:  mysql&lt;br /&gt;database: sample_development&lt;br /&gt;username: root&lt;br /&gt;password:&lt;br /&gt;host:     localhost&lt;br /&gt;&lt;br /&gt;test:&lt;br /&gt;&lt;&lt;:       *defaults        &lt;br /&gt;database: sample_test            &lt;br /&gt;&lt;br /&gt;production:        &lt;br /&gt;&lt;&lt;:       *defaults         &lt;br /&gt;database: sample_production      &lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Next, let's create a resource:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;merb-gen resource Post title:string body:text created_at:date_time&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(&lt;em&gt;NOTE: Run merb-gen with no arguments to see a complete list of generators.&lt;/em&gt;)&lt;/p&gt;&lt;p&gt;Make sure that you use 'date_time' and not 'datetime' as you would with ActiveRecord. Otherwise, the created_at field will be assigned the type 'Datetime'  (which is wrong), and not the correct 'DateTime'. One other potential gotcha - DataMapper strings will generate a varchar(50) field in MySQL, not varchar(255) like in ActiveRecord.&lt;/p&gt;&lt;p&gt;The merb-gen command will generate a Post model at app/models/post.rb, among other files. Take a look at the file now:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;class Post&lt;br /&gt;include DataMapper::Resource&lt;br /&gt;&lt;br /&gt;property :title, String&lt;br /&gt;property :body, Text&lt;br /&gt;property :created_at, DateTime&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You will need to add a property (I put it above the other properties):&lt;/p&gt;&lt;div class="CodeRay"&gt;property :id, Integer, :serial =&gt; true&lt;/div&gt;&lt;br /&gt;&lt;p&gt;because DataMapper requires you to explicitly declare the primary key. Next, go ahead and run the migration:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;rake dm:db:automigrate&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that the &lt;code&gt;dm:db:automigrate &lt;/code&gt;task is destructive. If you create any posts, then run the task again, the table will be dropped and recreated, causing you to lose your data.&lt;/p&gt;&lt;p&gt;You will also need to edit config/router.rb, because Merb doesn't add the Post resource to the routes automatically:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;br /&gt;Merb::Router.prepare do |r|&lt;br /&gt;# RESTful routes&lt;br /&gt;r.resources :posts&lt;br /&gt;end&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now let's take a look at the views (the posts controller at app/controllers/posts.rb should have everything you need from the merb-gen resource command). I modified my app/views/posts/new.html.erb file to look like this:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;&amp;lt;h1&amp;gt;New Post&amp;lt;/h1&amp;gt;&lt;br /&gt;&amp;lt;%= error_messages_for :post %&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;% form_for(:post, :action =&gt; url(:posts) do %&amp;gt;&lt;br /&gt;&amp;lt;%= partial('form', :button_text =&gt; 'Create') %&amp;gt;&lt;br /&gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;%= link_to 'Back', url(:posts) %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;I moved the form elements into a form partial at app/views/posts/_form.html.erb:&lt;/p&gt;&lt;br /&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;p&amp;gt;&lt;br /&gt;&amp;lt;label for="post_title"&amp;gt;Title: &amp;lt;/label&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;&amp;lt;%= text_control :title %&amp;gt;&lt;br /&gt;&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;p&amp;gt;&lt;br /&gt;&amp;lt;label for="post_body"&amp;gt;Body: &amp;lt;/label&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;&amp;lt;%= text_area_control :body %&amp;gt;&lt;br /&gt;&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;p&amp;gt;&lt;br /&gt;&amp;lt;%= submit_button button_text %&amp;gt;&lt;br /&gt;&amp;lt;/p&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You can probably guess what the edit view looks like.&lt;/p&gt;&lt;p&gt;Let's fire up merb and take a look in the browser:&lt;/p&gt;&lt;div class="CodeRay"&gt;$ merb&lt;/div&gt;&lt;br /&gt;&lt;p&gt;(&lt;em&gt;NOTE: enter 'merb --help' to see a complete list of options to the 'merb' command&lt;/em&gt;). &lt;/p&gt;&lt;p&gt;Now open up your favorite browser and navigate to 'http://localhost:4000/posts'. You should see something very like this:&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_mJ0xZxxa46A/SKF7UueUVZI/AAAAAAAAAAc/zme2tfhNNI4/s1600-h/Picture+1.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_mJ0xZxxa46A/SKF7UueUVZI/AAAAAAAAAAc/zme2tfhNNI4/s320/Picture+1.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5233599837984019858" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Now go ahead and create your first post!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8427238914290520785-8597637737797183833?l=domainspecific.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://domainspecific.blogspot.com/feeds/8597637737797183833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8427238914290520785&amp;postID=8597637737797183833' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8427238914290520785/posts/default/8597637737797183833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8427238914290520785/posts/default/8597637737797183833'/><link rel='alternate' type='text/html' href='http://domainspecific.blogspot.com/2008/08/sample-application-using-edge-merb-and.html' title='Sample Application Using Edge Merb and DataMapper'/><author><name>Doug</name><uri>http://www.blogger.com/profile/02033627970527658208</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_mJ0xZxxa46A/SKF7UueUVZI/AAAAAAAAAAc/zme2tfhNNI4/s72-c/Picture+1.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8427238914290520785.post-394036699361539714</id><published>2008-08-11T13:19:00.001-07:00</published><updated>2008-08-12T13:36:52.508-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='datamapper'/><category scheme='http://www.blogger.com/atom/ns#' term='merb'/><title type='text'>Edge Merb and DataMapper on Leopard</title><content type='html'>&lt;p&gt;After doing this a few times, I decided I'd document my steps for getting edge Merb with DataMapper up and running on a Leopard box. Be forewarned: when working with edge Merb and DataMapper, be prepared to deal with things breaking, at least until Merb gets to 1.0.&lt;/p&gt;&lt;p&gt;First, install the gems that Merb depends on:&lt;/p&gt;&lt;div class="CodeRay"&gt;$ sudo gem install english erubis hpricot json_pure mime-types rack&lt;/div&gt;&lt;p&gt;Next, install Git. You can try &lt;a href="http://dysinger.net/2007/12/30/installing-git-on-mac-os-x-105-leopard/"&gt;installing Git from source&lt;/a&gt; if you want, but &lt;a href="http://macports.org/"&gt;MacPorts&lt;/a&gt; worked fine for me. &lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;$ sudo port install git-core&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once you have Git installed, head on over to &lt;a href="http://www.github.com/"&gt;Github&lt;/a&gt; to start cloning the various repositories you'll need. I suggest creating one directory where you keep all your Merb-related repositories - I keep mine in &lt;code&gt;~/dev/merb&lt;/code&gt;.&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;$ git clone git://github.com/sam/extlib.git&lt;br /&gt;$ git clone git://github.com/wycats/merb-core.git&lt;br /&gt;$ git clone git://github.com/wycats/merb-more.git&lt;br /&gt;$ git clone git://github.com/wycats/merb-plugins.git&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These are the four main repositories for Merb. As the names suggest, if you wanted to just do barebones Merb hacking, you could get by with just merb-core and skip merb-more and merb-plugins. But in my experience, you're going to want them eventually, so I advise just installing them now. &lt;/p&gt;&lt;p&gt;Now we'll install each gem:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;$ cd extlib&lt;br /&gt;$ sudo rake install&lt;br /&gt;$ cd ../merb-core&lt;br /&gt;$ sudo rake install&lt;br /&gt;$ cd ../merb-more&lt;br /&gt;$ sudo rake install&lt;br /&gt;$ cd ../merb-plugins&lt;br /&gt;$ sudo rake install&lt;br /&gt;$ cd ..&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Congratulations, you now have edge Merb installed!&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Next, let's install edge DataMapper. First, install the addressable gem, a dependency of data_objects:&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;sudo gem install addressable&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, change directories back into your top-level Merb directory, if you haven't already by following the instructions above, and clone the necessary repositories.&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;$ git clone git://github.com/sam/do.git&lt;br /&gt;$ git clone git://github.com/sam/dm-core.git&lt;br /&gt;$ git clone git://github.com/sam/dm-more.git&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now go ahead and install the DataMapper dependencies and gems (&lt;em&gt;NOTE - I got an error related to the PostgresSQL install here, but I don't use it. It may affect you however.&lt;/em&gt;):&lt;/p&gt;&lt;div class="CodeRay"&gt;&lt;pre&gt;$ cd do&lt;br /&gt;$ sudo rake install&lt;br /&gt;$ cd ../dm-core&lt;br /&gt;$ sudo rake install&lt;br /&gt;$ cd ../dm-more&lt;br /&gt;$ sudo rake install&lt;br /&gt;$ cd ..&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Excellent, now you're ready to &lt;a href="http://domainspecific.blogspot.com/2008/08/sample-application-using-edge-merb-and.html"&gt;create a Merb app on the edge&lt;/a&gt;! &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8427238914290520785-394036699361539714?l=domainspecific.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://domainspecific.blogspot.com/feeds/394036699361539714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8427238914290520785&amp;postID=394036699361539714' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8427238914290520785/posts/default/394036699361539714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8427238914290520785/posts/default/394036699361539714'/><link rel='alternate' type='text/html' href='http://domainspecific.blogspot.com/2008/08/edge-merb-and-datamapper-on-leopard.html' title='Edge Merb and DataMapper on Leopard'/><author><name>Doug</name><uri>http://www.blogger.com/profile/02033627970527658208</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8427238914290520785.post-6708785479347745422</id><published>2008-05-01T06:52:00.000-07:00</published><updated>2008-08-12T05:53:11.128-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><title type='text'>5 Rails Tips</title><content type='html'>&lt;dl&gt;Here's my entry for the &lt;a href="http://railscasts.com/contest"&gt;Railscasts 100th Episode Contest&lt;/a&gt; - hope you find these tips useful.&lt;/dl&gt;&lt;dl&gt;&lt;br /&gt;&lt;dt&gt;1. Create SEO friendly URLs for multi-word resources with edge Rails&lt;/dt&gt;&lt;br /&gt;&lt;dd&gt;&lt;br /&gt;&lt;p&gt;Let's say you're creating a web application that documents various aspects of computers. Naturally, you're going to want to  be like all the cool kids and make your application RESTful. Let's go ahead and create a resource for operating systems:&lt;/p&gt;&lt;br /&gt;&lt;span class="CodeRay line"&gt;$ ruby script/generate resource OperatingSystem&lt;/span&gt;&lt;br /&gt;&lt;p&gt;When running the app locally, by default you'll find this resource at localhost:3000/operating_systems. But in order to get the best bang for your SEO buck, you should use hyphens in your URLs (&lt;a href="http://www.searchenginejournal.com/google-underscores-hyphens/6010/"&gt;http://www.searchenginejournal.com/google-underscores-hyphens/6010/&lt;/a&gt;). The solution for edge Rails is to use the :as option to map.resources in config/routes.rb. First, freeze edge Rails into your app:&lt;/p&gt;&lt;br /&gt;&lt;span class="CodeRay line"&gt;$ rake rails:freeze:edge&lt;/span&gt;&lt;br /&gt;&lt;p&gt;Then, update config/routes.rb with the following:&lt;/p&gt;&lt;br /&gt;&lt;span class="CodeRay line"&gt;map.resources &lt;span class="sy"&gt;:operating_systems&lt;/span&gt;, &lt;span class="sy"&gt;:as&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;'operating-systems'&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;p&gt;Voila! Now you can browse to your operating system resource at localhost:3000/operating-systems.&lt;/p&gt;&lt;br /&gt;&lt;/dd&gt;&lt;br /&gt;&lt;dt&gt;2. ActiveResource != ActiveRecord&lt;/dt&gt;&lt;br /&gt;&lt;dd&gt;&lt;p&gt;The team that has worked on ActiveResource has done a great job of making using it as painless as possible. On the surface, consuming a RESTful service seems very similar to using ActiveRecord with a database. It's easy to assume that everything works the same way. Don't fall into that trap.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Make sure you're aware of what's going on behind the scenes. Tail your logs and take a look at the calls that ActiveResource is making. Let's say you write an app that displays the weather, and you have a Forecast model. At first, your app is built using ActiveRecord. You may have a place in your code that calls Forecast.find(:first). This will generate the following call:&lt;/p&gt;&lt;br /&gt;&lt;span class="CodeRay line"&gt;SELECT * FROM forecasts LIMIT 1;&lt;/span&gt;&lt;br /&gt;&lt;p&gt;After a while, you get tired of typing in the forecast, so you decide to switch to using a web service that does it for you. The only problem is that the same Forecast.find(:first) will generate the following service call:&lt;/p&gt;&lt;br /&gt;&lt;span class="CodeRay line"&gt;GET http://url_for_web_service.com/forecasts&lt;/span&gt;&lt;br /&gt;&lt;p&gt;That means you're getting all the forecasts, and then ActiveResource is selecting the first one for you. That could be a big problem if there's 10,000 forecasts. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;So keep an eye on your logs and be aware of the subtle differences.&lt;/p&gt;&lt;br /&gt;&lt;/dd&gt;&lt;br /&gt;&lt;dt&gt;3. Working with collections in views&lt;/dt&gt;&lt;br /&gt;&lt;dd&gt;&lt;p&gt;When iterating through a collection in a view, one underused helper is &lt;code&gt;cycle&lt;/code&gt;. &lt;code&gt;cycle&lt;/code&gt; takes an array parameter with an optional name parameter. The first example in the official Rails documentation suggests using &lt;cycle&gt; to alternate CSS classes for tables rows:&lt;/cycle&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="CodeRay"&gt;&lt;br /&gt;&lt;span class="c"&gt;# Alternate CSS classes for even and odd numbers...&lt;/span&gt;&lt;br /&gt; &lt;span class="iv"&gt;@items&lt;/span&gt; = [1,2,3,4]&lt;br /&gt; &amp;lt;table&amp;gt;&lt;br /&gt; &amp;lt;% &lt;span class="iv"&gt;@items&lt;/span&gt;.each &lt;span class="r"&gt;do&lt;/span&gt; |item| %&amp;gt;&lt;br /&gt;   &amp;lt;tr class="&amp;lt;%= cycle("even", "odd") -%&amp;gt;"&amp;gt;&lt;br /&gt;     &amp;lt;td&amp;gt;item&amp;lt;/td&amp;gt;&lt;br /&gt;   &amp;lt;/tr&amp;gt;&lt;br /&gt; &amp;lt;% &lt;span class="r"&gt;end&lt;/span&gt; %&amp;gt;&lt;br /&gt; &amp;lt;/table&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Another solution for the same problem (if you have an array of numbers) is to make use of ActiveSupport's &lt;code&gt;odd?&lt;/code&gt; and &lt;code&gt;even?&lt;/code&gt; helpers:&lt;/p&gt;&lt;br /&gt;&lt;div class="CodeRay"&gt;&lt;br /&gt;&lt;span class="c"&gt;# Alternate CSS classes for even and odd numbers...&lt;/span&gt;&lt;br /&gt; &lt;span class="iv"&gt;@items&lt;/span&gt; = [1,2,3,4]&lt;br /&gt; &amp;lt;table&amp;gt;&lt;br /&gt; &amp;lt;% &lt;span class="iv"&gt;@items&lt;/span&gt;.each &lt;span class="r"&gt;do&lt;/span&gt; |item| %&amp;gt;&lt;br /&gt;   &amp;lt;tr class="&amp;lt;%= item.even ? "even" : "odd" -%&amp;gt;"&amp;gt;&lt;br /&gt;     &amp;lt;td&amp;gt;item&amp;lt;/td&amp;gt;&lt;br /&gt;   &amp;lt;/tr&amp;gt;&lt;br /&gt; &amp;lt;% &lt;span class="r"&gt;end&lt;/span&gt; %&amp;gt;&lt;br /&gt; &amp;lt;/table&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;When I need to keep track of the items in the collection, I most often end up using the &lt;code&gt;each_with_index&lt;/code&gt; method from Ruby's Enumerable module:&lt;/p&gt;&lt;br /&gt;&lt;div class="CodeRay"&gt;&lt;br /&gt;&lt;span class="c"&gt;# Alternate CSS classes for even and odd numbers...&lt;/span&gt;&lt;br /&gt; &lt;span class="iv"&gt;@items&lt;/span&gt; = [1,2,3,4]&lt;br /&gt; &amp;lt;table&amp;gt;&lt;br /&gt; &amp;lt;% &lt;span class="iv"&gt;@items&lt;/span&gt;.each_with_index &lt;span class="r"&gt;do&lt;/span&gt; |item, index| %&amp;gt;&lt;br /&gt;   &amp;lt;tr class="&amp;lt;%= index.even? ? "even" : "odd" -%&amp;gt;"&amp;gt;&lt;br /&gt;     &amp;lt;td&amp;gt;item&amp;lt;/td&amp;gt;&lt;br /&gt;   &amp;lt;/tr&amp;gt;&lt;br /&gt; &amp;lt;% &lt;span class="r"&gt;end&lt;/span&gt; %&amp;gt;&lt;br /&gt; &amp;lt;/table&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;This technique has the advantage of giving you the index of each item in the collection. This can come in handy when making Ajax calls - you can give the wrapping element an id that corresponds to the item's index:&lt;/p&gt;&lt;br /&gt;&lt;div class="CodeRay"&gt;&lt;br /&gt;&lt;span class="c"&gt;# Give each table row an id that uses the item's index in the collection&lt;/span&gt;&lt;br /&gt; &lt;span class="iv"&gt;@items&lt;/span&gt; = [1,2,3,4]&lt;br /&gt; &amp;lt;table&amp;gt;&lt;br /&gt; &amp;lt;% &lt;span class="iv"&gt;@items&lt;/span&gt;.each_with_index &lt;span class="r"&gt;do&lt;/span&gt; |item, index| %&amp;gt;&lt;br /&gt;   &amp;lt;tr id="item-&amp;lt;%= index %&amp;gt;"&amp;gt;&lt;br /&gt;     &amp;lt;td&amp;gt;item&amp;lt;/td&amp;gt;&lt;br /&gt;   &amp;lt;/tr&amp;gt;&lt;br /&gt; &amp;lt;% &lt;span class="r"&gt;end&lt;/span&gt; %&amp;gt;&lt;br /&gt; &amp;lt;/table&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;You now have the hook you need if you want to delete that table row with a subsequent Ajax call.&lt;/p&gt;&lt;br /&gt;&lt;/dd&gt;&lt;br /&gt;&lt;dt&gt;4. Keep your gems local, without Edge Rails&lt;/dt&gt;&lt;br /&gt;&lt;dd&gt;&lt;p&gt;Edge Rails has added the ability to explicitly declare your app's gem dependencies in config/environment.rb with the config.gem syntax. See Ryan Daigle's write-up at &lt;a href="http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies"&gt;http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies&lt;/a&gt; for a good description of the new functionality. Freeze Edge Rails into your apps and you'll see the following new Rake commands available:&lt;/p&gt;&lt;br /&gt;&lt;div class="CodeRay"&gt;&lt;br /&gt;$ rake -D gem&lt;br /&gt;&lt;br /&gt;rake gems&lt;br /&gt;  List the gems that this rails application depends on&lt;br /&gt;&lt;br /&gt;rake gems:build&lt;br /&gt;  Build any native extensions for unpacked gems&lt;br /&gt;&lt;br /&gt;rake gems:install&lt;br /&gt;  Installs all required gems for this application.&lt;br /&gt;&lt;br /&gt;rake gems:unpack&lt;br /&gt;  Unpacks the specified gem into vendor/gems.&lt;br /&gt;&lt;br /&gt;rake rails:freeze:gems&lt;br /&gt;  Lock this application to the current gems (by unpacking them into vendor/rails)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Even if you're not ready to use Edge Rails, you can ensure that your app will always have the gem code it depends on available. It's certainly not as clean, and it does take a little more work. Move into your vendor/plugins directory, and for each gem your app depends on, just do:&lt;/p&gt;&lt;br /&gt;&lt;span class="CodeRay line"&gt;$ sudo gem unpack &amp;lt;gem name&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;p&gt;This will unpack the given gem into vendor/plugins and ensure that the gem's code will be loaded when your app starts app. It's a nice way to ensure that your app will have everything it needs when, for example, you deploy on a shared host.&lt;/p&gt;&lt;br /&gt;&lt;/dd&gt;&lt;br /&gt;&lt;dt&gt;5. Keep a summary of your model schema inside the model&lt;/dt&gt;&lt;br /&gt;&lt;dd&gt;&lt;br /&gt;&lt;p&gt;One of the nice things about the DataMapper ORM (&lt;a href="http://datamapper.org/"&gt;http://datamapper.org/&lt;/a&gt;) is having the model's schema laid out right in the model code. When working with ActiveRecord models, I sometimes find myself returning to old code and forgetting what the schema was. Naturally, you could jump into script/console and do:&lt;/p&gt;&lt;br /&gt;&lt;span class="CodeRay line"&gt;&amp;gt;&amp;gt; ModelName.new.attributes&lt;/span&gt;&lt;br /&gt;&lt;p&gt;to see what's available. But that doesn't give you the full schema. The solution is Dave Thomas' &lt;code&gt;annotate_models&lt;/code&gt; plugin.&lt;/p&gt;&lt;br /&gt;&lt;span class="CodeRay line"&gt;$ ruby script/plugin install http://repo.pragprog.com/svn/Public/plugins/annotate_models/&lt;/span&gt;&lt;br /&gt;&lt;p&gt;The plugin adds a new rake task for you to generate the model annotations:&lt;/p&gt;&lt;br /&gt;&lt;span class="CodeRay line"&gt;$ rake annotate_models&lt;/span&gt;&lt;br /&gt;&lt;p&gt;Here's a sample of what the plugin adds to your model:&lt;/p&gt;&lt;br /&gt;&lt;div class="CodeRay"&gt;&lt;br /&gt;&lt;span class="CodeRay c"&gt;&lt;br /&gt;# Schema version: 3&lt;br /&gt;#&lt;br /&gt;# Table name: programs&lt;br /&gt;#&lt;br /&gt;#  id          :integer(11)     not null, primary key&lt;br /&gt;#  title       :string(255)&lt;br /&gt;#  description :text   &lt;br /&gt;#  asset_url   :string(255)&lt;br /&gt;#  link        :string(255)&lt;br /&gt;#  language    :string(255)&lt;br /&gt;#  author      :string(255)&lt;br /&gt;#&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="CodeRay r"&gt;class&lt;/span&gt; &lt;span class="CodeRay cl"&gt;Program&lt;/span&gt;&amp;lt;&lt;span class="CodeRay cl"&gt;ActiveRecord::Base&lt;/span&gt;&lt;br /&gt;&lt;span class="CodeRay r"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Please note that the &lt;code&gt;annotate_models&lt;/code&gt; plugin has been enhanced and released as a gem by Cuong Tran, among others. Source code is available at &lt;a href="http://github.com/ctran/annotate_models/tree/master"&gt;http://github.com/ctran/annotate_models/tree/master&lt;/a&gt;, and installation is as simple as:&lt;/p&gt;&lt;br /&gt;&lt;span class="CodeRay line"&gt;$ sudo gem install annotate-models&lt;/span&gt;&lt;br /&gt;&lt;/dd&gt;&lt;br /&gt;&lt;/dl&gt;&lt;br /&gt;&lt;p&gt;Okay, I said it would be only five tips, but here's one more:  get local documentation.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Just about everywhere you go these days, you can find an Internet connection. But just in case, I like to have both Ruby and Rails documentation on my laptop. Download the Ruby documentation here: &lt;a href="http://www.ruby-doc.org/downloads"&gt;http://www.ruby-doc.org/downloads&lt;/a&gt; and the Rails documentation here: &lt;a href="http://www.railsbrain.com"&gt;http://www.railsbrain.com&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;That's it for this post. Good luck with your next Rails app!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8427238914290520785-6708785479347745422?l=domainspecific.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://domainspecific.blogspot.com/feeds/6708785479347745422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8427238914290520785&amp;postID=6708785479347745422' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8427238914290520785/posts/default/6708785479347745422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8427238914290520785/posts/default/6708785479347745422'/><link rel='alternate' type='text/html' href='http://domainspecific.blogspot.com/2008/05/5-rails-tips.html' title='5 Rails Tips'/><author><name>Doug</name><uri>http://www.blogger.com/profile/02033627970527658208</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
