<?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-21714662</id><updated>2011-12-08T06:14:13.882-08:00</updated><category term='RESTful'/><category term='MySQL'/><category term='Functional Programming'/><category term='Ruby'/><category term='Database'/><category term='TextMate'/><category term='Rails'/><category term='1.9.2'/><category term='Debugging'/><category term='Benchmarking'/><category term='Rake'/><category term='Capistrano'/><category term='Rspec'/><title type='text'>Working with Rails</title><subtitle type='html'>President of Development Leverage (http://devleverage.com). Ruby on Rails Fan.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-21714662.post-4065208094625397828</id><published>2011-06-02T20:05:00.000-07:00</published><updated>2011-06-02T20:17:43.860-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Capistrano'/><category scheme='http://www.blogger.com/atom/ns#' term='Database'/><category scheme='http://www.blogger.com/atom/ns#' term='Rake'/><title type='text'>Using Capistrano and Rake for DB Maintenance</title><content type='html'>I know that periodically it's a good idea to run &lt;a href="http://dev.mysql.com/doc/refman/5.6/en/analyze-table.html"&gt;analyze table&lt;/a&gt; on tables in your mysql database so they have updated statistics for the query optimizer to use.&lt;br /&gt;&lt;br /&gt;Until now, I've generally done it manually by shelling into a machine, connecting to mysql at the command line and running the commands.  Not a big deal, or a big time sink, but it seemed ripe for some automation.&lt;br /&gt;&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;#lib/tasks/database.rake&lt;br /&gt;namespace :db do&lt;br /&gt;  desc "Runs analyze table on each of the tables in the DB so that queries can be optimized correctly"&lt;br /&gt;  task :analyze_tables =&gt; :environment do&lt;br /&gt;    cmd = build_db_command('mysql')&lt;br /&gt;    &lt;br /&gt;    conn = ActiveRecord::Base.connection&lt;br /&gt;    tables = conn.tables.reject {|i| i == 'schema_info'}&lt;br /&gt;&lt;br /&gt;    db_command = "echo '"&lt;br /&gt;    db_command += tables.collect {|table| "analyze table #{table};"}.join(' ')&lt;br /&gt;    db_command += "' | " + cmd&lt;br /&gt;&lt;br /&gt;    puts "Running analyze tables on: #{tables.join(', ')}"&lt;br /&gt;    puts %x[#{db_command}]&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;the cool thing here is using ActiveRecord::Base.connection.tables to get a list of all the tables in your database.  Once I have those, I turn them into a string of commands that I use echo to pipe to mysql.&lt;br /&gt;&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint sh"&gt;echo 'analyze table posts; analyze table comments; analyze table users; | mysql -u deploy -psecret blog_production '&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;since I have other commands that interact with mysql, I created a method &lt;pre&gt;build_db_command&lt;/pre&gt; that builds a mysql command using the configuration in your database.yml file.&lt;br /&gt;&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;#lib/tasks/database.rake&lt;br /&gt;&lt;br /&gt;def build_db_command(executable)&lt;br /&gt;  abc = ActiveRecord::Base.configurations[RAILS_ENV]&lt;br /&gt;  case abc['adapter']&lt;br /&gt;  when 'mysql'&lt;br /&gt;    cmd = [executable]&lt;br /&gt;    cmd &lt;&lt; "--host='#{abc['host']}'" unless abc['host'].blank?&lt;br /&gt;    cmd &lt;&lt; "--user='#{abc['username'].blank? ? 'root' : abc['username']}'"&lt;br /&gt;    cmd &lt;&lt; "--password='#{abc['password']}'" unless abc['password'].blank?&lt;br /&gt;    cmd &lt;&lt; abc['database']&lt;br /&gt;    &lt;br /&gt;    cmd.flatten.join(' ')&lt;br /&gt;  else&lt;br /&gt;    raise "Task not supported by '#{abc['adapter']}'."&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In order to make this rake task accessible through capistrano, I used &lt;a href="https://github.com/rubaidh"&gt;rubaidh's approach&lt;/a&gt;:&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;#config/recipies.rb&lt;br /&gt;def rubaidh_run_rake(*tasks)&lt;br /&gt;  rake = fetch(:rake, '/usr/local/bin/rake')&lt;br /&gt;  rails_env = fetch(:rails_env, 'production')&lt;br /&gt;&lt;br /&gt;  tasks.each do |task|&lt;br /&gt;    run "cd #{latest_release}; #{rake} RAILS_ENV=#{rails_env} #{task}"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;namespace :db do&lt;br /&gt;  desc "Run through all the tables in the DB and run analyze_table on them"&lt;br /&gt;  task :analyze_tables, :roles =&gt; :db, :only =&gt; { :primary =&gt; true } do&lt;br /&gt;    rubaidh_run_rake "db:analyze_tables"&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;voila!  Now I can just&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;cap db:analyze_tables&lt;/code&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-4065208094625397828?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/4065208094625397828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=4065208094625397828' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/4065208094625397828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/4065208094625397828'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2011/06/running-db-maintenance-tasks-through.html' title='Using Capistrano and Rake for DB Maintenance'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-1657686382606003634</id><published>2010-09-20T11:32:00.001-07:00</published><updated>2010-09-20T12:37:15.194-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='1.9.2'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Benchmarking'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Benchmarking Functional vs Data Based Lists in Ruby</title><content type='html'>At GoGaRuCo 2010 (&lt;a href="http://gogaruco.com/"&gt;Golden Gate Ruby Conference&lt;/a&gt;), Jim Weirich (@jimweirich) gave a great keynote on Functional and Object Oriented programming in Ruby. In the pres, he threw up some code to implement lists using a simple data structure and alternatively as Procs that relied on closures to keep state.&lt;br /&gt;&lt;br /&gt;It seemed like it would take a lot more work for Ruby to build all these Proc objects, but I wasn't actually sure, so I decided to benchmark it.  As it turns out, the functional approach is the slowest, but it's closer to a data based approach than I would have expected.&lt;br /&gt;&lt;br /&gt;Here is Jim's code for the data structure based approach:&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;List = Struct.new(:head, :tail)&lt;br /&gt;Cons = -&gt;(h,t) { List.new(h,t) }&lt;br /&gt;Car = -&gt;(list) { list.head }&lt;br /&gt;Cdr = -&gt;(list) { list.tail }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;and here is his code for a Proc based approach (using the 1.9 syntax)&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;f_Cons = -&gt;(h,t) { -&gt;(s) { (s==:h) ? h : t } } &lt;br /&gt;f_Car = -&gt;(list) { list.(:h) } &lt;br /&gt;f_Cdr = -&gt;(list) { list.(:t) }&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;just out of curiosity, I also wrote a standard Class based approach as well (this uses the idiomatic object.message style rather than the "bare message" style which is more like what you'd see in a Lisp/Scheme based language)&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;class List2&lt;br /&gt;  attr_reader :car, :cdr&lt;br /&gt;&lt;br /&gt;  def initialize(car, cdr)&lt;br /&gt;    @car = car&lt;br /&gt;    @cdr = cdr&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def self.Cons(car, cdr)&lt;br /&gt;    List2.new(car, cdr)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Just to show that all the implementations are working&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;#Data based&lt;br /&gt;lst = Cons.(1, Cons.(Cons.(2, Cons.(3, nil)), Cons.(4, Cons.(5,nil))))&lt;br /&gt;raise "Problem with Car and Cdr" unless  Car.(Cdr.(Cdr.(l)))  == 4&lt;br /&gt;&lt;br /&gt;#Functional&lt;br /&gt;f_lst = f_Cons.(1, f_Cons.(f_Cons.(2, f_Cons.(3, nil)), f_Cons.(4, f_Cons.(5,nil))))&lt;br /&gt;raise "Problem with f_Car and f_Cdr" unless  f_Car.(f_Cdr.(f_Cdr.(f_lst)))  == 4&lt;br /&gt;&lt;br /&gt;#Class based&lt;br /&gt;c_lst = List2.Cons(1, List2.Cons(List2.Cons(2, List2.Cons(3, nil)), List2.Cons(4, List2.Cons(5,nil))))&lt;br /&gt;raise "Problem with List2.car and List2.cdr" unless  c_lst.cdr.cdr.car&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;and then I benchmarked them over 100,000 list creations and 5,000,000 extractions of the "4" from inside the list:&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;require 'benchmark'&lt;br /&gt;c = 100_000&lt;br /&gt;n = 5_000_000&lt;br /&gt;#this benchmarks creates and extracting the "4" from (1, (2, 3), 4, 5)&lt;br /&gt;Benchmark.bm do |rpt|&lt;br /&gt;  rpt.report("List Create")  { c.times do; Cons.(1, Cons.(Cons.(2, Cons.(3, nil)), Cons.(4, Cons.(5,nil)))); end;}&lt;br /&gt;  rpt.report("List Extract") { n.times do; Car.(Cdr.(Cdr.(lst))); end;}&lt;br /&gt;  rpt.report("Func Create")  { c.times do; f_Cons.(1, f_Cons.(f_Cons.(2, f_Cons.(3, nil)), f_Cons.(4, f_Cons.(5,nil)))); end;}&lt;br /&gt;  rpt.report("Func Extract")   { n.times do; f_Car.(f_Cdr.(f_Cdr.(f_lst))); end;}&lt;br /&gt;  rpt.report("Class Create")  { c.times do; List2.Cons(1, List2.Cons(List2.Cons(2, List2.Cons(3, nil)), List2.Cons(4, List2.Cons(5,nil)))); end;}&lt;br /&gt;  rpt.report("Class Extract")   { n.times do; c_lst.cdr.cdr.car; end;}&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;and got this for results (on a 2.8GHz MacBookPro from 2008)&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;               user     system      total        real&lt;br /&gt;List Create   0.270000   0.000000   0.270000 (  0.263856)&lt;br /&gt;List Extract  3.230000   0.000000   3.230000 (  3.238410)&lt;br /&gt;Func Create   0.630000   0.080000   0.710000 (  0.699868)&lt;br /&gt;Func Extract  6.410000   0.010000   6.420000 (  6.417965)&lt;br /&gt;Class Create  0.210000   0.000000   0.210000 (  0.217196)&lt;br /&gt;Class Extract 1.100000   0.000000   1.100000 (  1.090477)&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;So the Functional approach is definitely slower that the list based (2.6x on create, 2x on extract), but that was a smaller gap than I expected.&lt;br /&gt;&lt;br /&gt;I was also surprised that the Class based approach was so much faster than the List based approach (2.9x on extract) since the List implementation is just using Struct.new.  It looks like executing a "stubby proc" is quite a bit slower than running an instance method.&lt;br /&gt;&lt;br /&gt;For anyone who wants to play with this, all the code is up on github in a gist (&lt;a href="http://gist.github.com/588512"&gt;http://gist.github.com/588512&lt;/a&gt;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-1657686382606003634?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/1657686382606003634/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=1657686382606003634' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/1657686382606003634'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/1657686382606003634'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2010/09/benchmarking-functional-vs-data-based.html' title='Benchmarking Functional vs Data Based Lists in Ruby'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-8654742333512847870</id><published>2010-01-20T15:16:00.000-08:00</published><updated>2010-01-20T15:32:03.099-08:00</updated><title type='text'>Great resources for getting caching working on your rails app</title><content type='html'>I spent some time today getting caching of static assets up for a project I'm working on. Before picking a direction, I did a bunch of reading to understand different approaches.  At the end of it all, the things I found most helpful were:&lt;br /&gt;&lt;br /&gt;Stephen Sykes approach to getting Apache to automatically expire files that have the (automatically generated) timestamps that rails generates with image_tag, etc&lt;br /&gt;  &lt;a href="http://www.stephensykes.com/blog_perm.html?157"&gt;his blog post&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To test if that's working, you can use curl&lt;br /&gt;  curl --head http://yoursite.com/images/yourimage.png?1234567890&lt;br /&gt;(as shown in &lt;a href="http://www.dcmanges.com/blog/asset-versioning-in-rails"&gt;this post&lt;/a&gt; that actually describes a different way of doing things that I didn't go with)&lt;br /&gt;&lt;br /&gt;Once you've got caching of images from your erb files working, you can use &lt;a href="http://developer.yahoo.com/yslow/"&gt;YSlow&lt;/a&gt; to see your grade for Expires headers.&lt;br /&gt;&lt;br /&gt;If you're still getting a poor grade for expires headers, it's probably because you have CSS that includes references to images.&lt;br /&gt;&lt;br /&gt;In order to fix this, you basically want to append timestamps as query strings to the image URL's in your css file.  There are two basic ways to do this.&lt;br /&gt;&lt;br /&gt;One is to use controllers to generate your stylesheets from .erb files.  This allows you to use the rails image_tag helpers.  Since the resulting output files will be cached, this is pretty efficient.  For details, see &lt;a href="http://deaddeadgood.com/2009/9/28/far-future-expires-headers-for-css-images-in-rails"&gt;this blog post&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The second way (which I went with) is to use the very sweet plugin &lt;a href="http://github.com/redlinesoftware/css_asset_tagger"&gt;css-asset-tagger&lt;/a&gt;.  This is described by it's authors Redline in &lt;a href="http://weblog.redlinesoftware.com/2009/12/3/css-asset-tagger-rails-plugin/comments/1594#comment-1594"&gt;this blog post&lt;/a&gt;.  Basically, this works "automagically" to run through your css files after they are deployed on production and modify them by inserting timestamps after each image.  &lt;br /&gt;&lt;br /&gt;In either case, once the images in the CSS file also contain timestamps in the query strings, the expirations setup at the top will pick them up as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-8654742333512847870?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/8654742333512847870/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=8654742333512847870' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/8654742333512847870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/8654742333512847870'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2010/01/great-resources-for-getting-caching.html' title='Great resources for getting caching working on your rails app'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-297280871507031654</id><published>2009-11-30T12:33:00.000-08:00</published><updated>2009-11-30T12:44:34.396-08:00</updated><title type='text'>Clearing out content in content_for</title><content type='html'>In rails, multiple calls to content_for append their body's together and yield the concatenation of all the calls.  Conceptually, this looks something like:&lt;br /&gt;&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;&amp;lt;% content_for :title do %&gt;&lt;br /&gt;Hello&lt;br /&gt;&amp;lt;% end %&gt;&lt;br /&gt;&amp;lt;% content_for :title do %&gt;&lt;br /&gt;World&lt;br /&gt;&amp;lt;% end %&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;producing "Hello World" when you call&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;&amp;lt;% yield :title %&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In my current project, I was using redbox to create popup windows (see next post for details).  In some cases, I wanted to have multiple popup windows on the same page.  However, when I created those popups, each partial had a &lt;code&gt;content_for :title&lt;/code&gt; and I was ending up with later popups having titles that contained all the words from previous titles.&lt;br /&gt;&lt;br /&gt;After a little digging, I decided I needed a version of content_for that reset the value rather than appending to it.  I found some old patches for rails that changed how content_for worked, but I thought it would be cleaner to have a new method that set the content_for variable rather than patching the version in rails.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#config/initializers/set_content_for.rb&lt;/span&gt;&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;module ActionView&lt;br /&gt;  module Helpers&lt;br /&gt;    module CaptureHelper&lt;br /&gt;      def set_content_for(name, content = nil, &amp;block)&lt;br /&gt;        ivar = "@content_for_#{name}"&lt;br /&gt;        instance_variable_set(ivar, nil)&lt;br /&gt;        content_for(name, content, &amp;block)&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;by putting this in &lt;code&gt;/config/initializers&lt;/code&gt; it's automatically loaded by rails at startup.  You use it just like you'd use content_for&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;&amp;lt;% set_content_for :title do %&gt;&lt;br /&gt;...whatever...&lt;br /&gt;&amp;lt;end %&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;but it clears out the current value of the section before setting it to the content of your new block.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-297280871507031654?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/297280871507031654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=297280871507031654' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/297280871507031654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/297280871507031654'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2009/11/clearing-out-content-in-contentfor.html' title='Clearing out content in content_for'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-3663945417416100028</id><published>2009-11-30T11:52:00.000-08:00</published><updated>2009-11-30T12:32:33.364-08:00</updated><title type='text'>Using a modal layout with redbox for popup windows</title><content type='html'>In my current project, I've been using &lt;a href="http://www.craigambrose.com/projects/redbox"&gt;redbox&lt;/a&gt; for popup windows.  By default, these come up as a plain white box, so I wanted to style them with a colored area for a title, a region at the bottom for buttons, etc.  So I created a layout that has all the styles&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#app/views/layouts/_modal.erb&lt;/span&gt;&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;&amp;lt;div class="modal_box"&gt;&lt;br /&gt;  &amp;lt;div id="title"&gt;&lt;br /&gt;   &amp;lt;h3&gt;&lt;br /&gt;      &amp;lt;%= yield :title %&gt;&lt;br /&gt;      &amp;lt;span&gt;&amp;lt;%= link_to_close_redbox 'close' %&gt;&amp;lt;/span&gt;&lt;br /&gt;   &amp;lt;/h3&gt;&lt;br /&gt;  &amp;lt;/div&gt;&lt;br /&gt;  &amp;lt;div id="modal_flashes"&gt;&lt;br /&gt;    &amp;lt;%= render :partial =&gt; '/layouts/flashes' %&gt;&lt;br /&gt;  &amp;lt;/div&gt;&lt;br /&gt;  &amp;lt;%= yield %&gt;&lt;br /&gt;&amp;lt;/div&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;then to create a modal window, I just create a partial with the content I want to appear in the modal window&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#app/views/wizard/_advice.html.erb&lt;/span&gt;&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;&amp;lt;% content_for :title do %&gt;&lt;br /&gt;  How to...&lt;br /&gt;&amp;lt;% end %&gt;&lt;br /&gt;&amp;lt;div class="modal_content content_section"&gt;&lt;br /&gt;  &amp;lt;p&gt;As the ...&amp;lt;/p&gt;&lt;br /&gt;&amp;lt;/div&gt;&lt;br /&gt;&amp;lt;div class="actions"&gt;&lt;br /&gt;  &amp;lt;%= link_to_close_redbox 'Close', :class =&gt; "modal_action_link"  %&gt;&lt;br /&gt;&amp;lt;/div&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;and render that partial in a hidden div on my main view&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#app/views/wizard/page1.html.erb&lt;/span&gt;&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;&amp;lt;div id="advice" style="display:none;"&gt;&lt;br /&gt;  &amp;lt;%= render :partial =&gt; 'advice', :layout =&gt; '/layouts/modal' %&gt;&lt;br /&gt;&amp;lt;/div&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;that is pulled by by a link_to_redbox call&lt;br /&gt;&lt;div class="code_block"&gt;&lt;code class="prettyprint rb"&gt;&amp;lt;%= link_to_redbox 'advice?', 'advice' %&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In this case, I could have gone farther and pushed more of the styling &amp; divs into the modal template.  Then I would have had additional content_for's for :body and :actions.  I didn't do that because in other places I needed to have the the popups display forms which included content in the body and submit buttons down in the actions.  By making everything other than the title the be the content that was yielded, that was easy to do.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-3663945417416100028?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/3663945417416100028/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=3663945417416100028' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/3663945417416100028'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/3663945417416100028'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2009/11/using-modal-layout-with-redbox-for.html' title='Using a modal layout with redbox for popup windows'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-1397276987806107434</id><published>2009-09-25T21:16:00.001-07:00</published><updated>2009-09-25T21:20:33.030-07:00</updated><title type='text'>Watching the International Space Station</title><content type='html'>Allison, Jessie and I just got back from sitting on Skyline Boulevard watching the International Space Station shoot across the sky.  It was super bright and it's very cool to watch this "star" streak across the sky and know that there are people living and working on it.&lt;br /&gt;&lt;br /&gt;If you want to check it out, go to&lt;br /&gt;&lt;a href="http://www.heavens-above.com/"&gt;http://www.heavens-above.com/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;and put in your latitude and longitude to see when the ISS will be visible from where you live.&lt;br /&gt;&lt;br /&gt;To find your latitude and longitude, pull up your home address on google maps and then paste&lt;br /&gt;&lt;code&gt;&lt;br /&gt;javascript:void(prompt('',gApplication.getMap().getCenter()));&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;into the place you normally enter URL's.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-1397276987806107434?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/1397276987806107434/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=1397276987806107434' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/1397276987806107434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/1397276987806107434'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2009/09/watching-international-space-station.html' title='Watching the International Space Station'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-3281103030850041095</id><published>2009-07-16T16:12:00.000-07:00</published><updated>2010-09-20T12:33:16.726-07:00</updated><title type='text'>DRYing Up Views Between Browser and Mobile Versions (across MIME types)</title><content type='html'>I was working on an app and decided that in order for it to be truly usable on mobile devices (iPhone, Blackberry, etc), it needed to have views that were tailored for small screens.&lt;br /&gt;&lt;br /&gt;I started by registering a new MIME type 'mobile' so I could detect it, and respond_to mobile requests appropriately.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#config/initializers/mime_types.rb&lt;/span&gt;&lt;br /&gt;&lt;div class="code_block"&gt;&lt;br /&gt;&lt;code class="prettyprint rb"&gt;&lt;br /&gt;Mime::Type.register_alias "text/html", :mobile&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;However, I quickly ran into a problem.  I was duplicating a lot of code between my abc.html.erb views and my new abc.mobile.erb views.  The obvious solution was to use partials.  However, the *.mobile.erb views were failing to load the partials I already had.&lt;br /&gt;&lt;br /&gt;What I realized after a little playing around was that if you have a view with a declared MIME type (new.mobile.erb) and you try to render a partial&lt;br /&gt;&lt;div class="code_block"&gt;&lt;br /&gt;&lt;code class="prettyprint rb"&gt;&lt;br /&gt;&amp;lt;%= render :partial =&gt; 'posts' %&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;Rails will look for partials with the same MIME type (_posts.mobile.erb), but it will not find partials with other MIME types (_posts.html.erb).  However, the solution is to take the MIME type out of the partial (_posts.erb), then the partial will be found when called from either an HTML or a Mobile view.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-3281103030850041095?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/3281103030850041095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=3281103030850041095' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/3281103030850041095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/3281103030850041095'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2009/07/drying-up-views-between-browser-and.html' title='DRYing Up Views Between Browser and Mobile Versions (across MIME types)'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-6779725317475109110</id><published>2009-06-09T09:32:00.000-07:00</published><updated>2009-06-09T10:13:42.176-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RESTful'/><category scheme='http://www.blogger.com/atom/ns#' term='Rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>RSpec route_for &amp; params_from with Nested Routes &amp; Custom Methods</title><content type='html'>I was just writing some route specs for nested routes that used PUT methods and it took some searching and experimentation to get it to work.  I didn't find a lot of relevant documentation, so hopefully this will help others.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;#routes.rb&lt;/span&gt;&lt;br /&gt;&lt;div class="code_block"&gt;&lt;br /&gt;&lt;code class="prettyprint rb"&gt;map.resources :accounts do |account|&lt;br /&gt;  account.resources :accounts_users, &lt;br /&gt;    :member =&gt; {:upgrade =&gt; :put, :downgrade =&gt; :put}&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Testing the generator (route_for)&lt;/span&gt;&lt;br /&gt;&lt;div class="code_block"&gt;&lt;br /&gt;&lt;code class="prettyprint rb"&gt;route_for(:controller =&gt; "accounts_users", &lt;br /&gt;          :action =&gt; "upgrade",&lt;br /&gt;          :account_id =&gt; "3",&lt;br /&gt;          :id =&gt; "5").should == &lt;br /&gt;  {:path =&gt; "/accounts/3/accounts_users/5/upgrade",&lt;br /&gt;   :method =&gt; 'put'}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;In this case rather than matching the output of route_for against a simple string, you match it against a hash with :path and :method&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Testing the recognition (params_from)&lt;/span&gt;&lt;br /&gt;&lt;div class="code_block"&gt;&lt;br /&gt;&lt;code class="prettyprint rb"&gt;params_from(:put, &lt;br /&gt;  "/accounts/3/accounts_users/1/upgrade").should == &lt;br /&gt;  {:controller =&gt; "accounts_users", :action =&gt; "upgrade",&lt;br /&gt;   :id =&gt; "1", :account_id =&gt; "3"}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-6779725317475109110?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/6779725317475109110/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=6779725317475109110' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/6779725317475109110'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/6779725317475109110'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2009/06/rspec-routefor-params-from-with-nested.html' title='RSpec route_for &amp; params_from with Nested Routes &amp; Custom Methods'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-282937308373640306</id><published>2008-01-16T12:49:00.000-08:00</published><updated>2008-01-16T12:56:00.333-08:00</updated><title type='text'>Cool way to test controllers that are protected by an authentication system</title><content type='html'>Whenever you've got a Rails app that has a login system, you tend to run into problems testing your controllers because the before_filter :login_required (or whatever you've called it) fires before you get to any of the controller logic you want to test.&lt;br /&gt;&lt;br /&gt;So you typically end up adding stuff to your tests to fake out the login tests ... either by manually creating a session that will pass the before_filter or by actually including code to do a valid login in the setup (before) for the test.&lt;br /&gt;&lt;br /&gt;I just came across a blog post:&lt;br /&gt;&lt;a href="http://www.vaporbase.com/postings/Using_Rspec_on_Controllers"&gt;Using Rspec On Controllers&lt;/a&gt; that points out that you can very simply avoid this problem by stubbing out the method being called by the before_filter:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;controller.stub!(:myfilter).and_return(true)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Sweet!&lt;br /&gt;&lt;br /&gt;-Steve&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-282937308373640306?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/282937308373640306/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=282937308373640306' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/282937308373640306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/282937308373640306'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2008/01/cool-way-to-test-controllers-that-are.html' title='Cool way to test controllers that are protected by an authentication system'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-1913356560610105052</id><published>2007-12-25T00:36:00.000-08:00</published><updated>2007-12-25T00:41:12.797-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RESTful'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Nice Post on Controllers that extend an API</title><content type='html'>I just read Nathan's post on RESTful controllers:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://functionalform.blogspot.com/2007/05/rest.html"&gt;REST: From theory to practice&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I found this article helpful.  One of the things about RESTful applications that always felt awkward was how to go beyond controllers that fronted a model object.  I thought the examples in this post made sense as concrete examples of where you would want to create "subcontrollers" that provide an extended API and additionally functionality for a single model.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-1913356560610105052?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/1913356560610105052/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=1913356560610105052' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/1913356560610105052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/1913356560610105052'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2007/12/nice-post-on-controllers-that-extend.html' title='Nice Post on Controllers that extend an API'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-5778372681752883217</id><published>2007-08-13T15:36:00.000-07:00</published><updated>2007-08-13T15:59:12.130-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='TextMate'/><category scheme='http://www.blogger.com/atom/ns#' term='Debugging'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Talk on RDebug from the SF Ruby Meetup</title><content type='html'>I had a chance to speak at the August 13th Ruby Meetup in San Francisco.  Here are the slides about RDebug and using it with Rails.&lt;br /&gt;&lt;span class="on" style="display: block;" id="formatbar_CreateLink" title="Link" onmouseover="ButtonHoverOn(this);" onmouseout="ButtonHoverOff(this);" onmouseup="" onmousedown="CheckFormatting(event);FormatbarButton('richeditorframe', this, 8);ButtonMouseDown(this);"&gt;&lt;br /&gt;&lt;a href="http://dev.proaptitude.com/public/RDebugPres.pdf"&gt;The slides&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;url&gt;&lt;/url&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-5778372681752883217?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/5778372681752883217/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=5778372681752883217' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/5778372681752883217'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/5778372681752883217'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2007/08/talk-on-rdebug-from-sf-ruby-meetup.html' title='Talk on RDebug from the SF Ruby Meetup'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-3540990464421333091</id><published>2007-01-08T15:16:00.000-08:00</published><updated>2007-01-25T11:32:47.634-08:00</updated><title type='text'>Installing QTRuby on Mac OSX</title><content type='html'>Over the last few weeks, I've been working to get QT3 working with Ruby.  I've been using the book &lt;span style="font-style: italic;"&gt;Rapid GUI Development with QtRuby&lt;/span&gt; by Caleb Tennis published by Pragmatic Programers (&lt;a href="http://www.pragmaticprogrammer.com/titles/ctrubyqt/index.html"&gt;http://www.pragmaticprogrammer.com/titles/ctrubyqt/index.html&lt;/a&gt;).  I think the book is an excellent introduction to Qt on Ruby.&lt;br /&gt;&lt;br /&gt;However, since the book was written a number of things have changed in the versions of software available and the build process and the instructions for Mac OSX as provided in the text aren't exactly right.&lt;br /&gt;&lt;br /&gt;Caleb Tennis (the author) has been kind enough to help me get through the installation problems via email, but I wanted to pull everything together into one place to help other Mac users.  The text below explains what I've done to get things working on PPC and Intel Macs.&lt;br /&gt;&lt;br /&gt;-------------------&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Getting Qt Running&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;in Safari, go to&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ftp://ftp.trolltech.com/qt/source&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This will mount the trolltech's source directory in Finder and open a window&lt;br /&gt;&lt;br /&gt;In the search box, type qt-mac-free and you'll see the mac releases.  If you scroll down, you'll see that the most recent release of version 3 is 3.3.7.&lt;br /&gt;&lt;br /&gt;Drag and drop "qt-mac-free-3.3.7.tar.gz" onto your Desktop.  Once the 15.7mb file has downloaded, eject the mounted source drive (drag it's icon to the trash, or right click and select eject).&lt;br /&gt;&lt;br /&gt;Double click the tar.gz file on your desktop and it will uncompress into a folder named "qt-mac-free-3.3.7".  You can delete the .tar.gz and the .tar files now.&lt;br /&gt;&lt;br /&gt;open a terminal window and (1) move the Qt 3.3.7 folder to /Developer&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;mv ~/Desktop/qt-mac-free-3.3.7 /Developer&lt;/span&gt;&lt;br /&gt;and create a symbolic link called "qt" to that directory&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;cd /Developer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  ln -s qt-mac-free-3.3.7 qt&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The next thing you need to do is setup environment variables for Qt.&lt;br /&gt;In the INSTALL file, Qt asks you to put these in .profile if you are using BASH as your shell (BASH is the Tiger default).  However, that didn't work for me.&lt;br /&gt;&lt;br /&gt;I needed to put them in&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    .bash_profile&lt;/span&gt;&lt;br /&gt;in order for them to be picked up.&lt;br /&gt;&lt;br /&gt;So edit your ~/.bash_profile file (emacs, vim, whatever) and add:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; ##########&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; # Setup for Qt3&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; ##########&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; QTDIR=/Developer/qt&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; PATH=$QTDIR/bin:$PATH                                                           &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; DYLD_LIBRARY_PATH=$QTDIR/lib:$DYLD_LIBRARY_PATH                                 &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;  export QTDIR PATH DYLD_LIBRARY_PATH&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;close the existing terminal you've been using for editing &amp; open a new one.  This will force your .bash_profile to be executed and you can verify that all variables are being correctly set by typing&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;env&lt;/span&gt;&lt;br /&gt;and scanning for QTDIR and that PATH and DYLD_LIBRARY_PATH exist and have&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/Developer/qt&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  /Developer/qt/bin&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  /Developer/qt/lib&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Make a symbolic link for the Qt Documentation&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    ln -s $QTDIR/doc/man $QTDIR/man&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Build Qt by doing:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  cd $QTDIR&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   ./configure -thread -no-tablet &lt;/span&gt;&lt;br /&gt;(you need to configure the -thread version for QtRuby to work)&lt;br /&gt;&lt;br /&gt;type "yes" to accept the terms of the license&lt;br /&gt;&lt;br /&gt;once the configure completes, build the software:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   /usr/bin/make&lt;/span&gt;&lt;br /&gt;(this took about an hour on a 2GHz G5)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;--NOTE: The next step (symbolic links) is NOT necessary if you set DYLD_LIBRARY_PATH as described above&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;--However, it is part of the Qt Install instructions so I'm including it for completeness&lt;/span&gt;&lt;br /&gt;setup symbolic links for the dynamic libraries&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    sudo ln -sf $QTDIR/lib/libqt-mt.3.dylib /usr/lib&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    sudo ln -sf $QTDIR/lib/libqui.1.dylib /usr/lib&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;verify Qt built correctly by running the Demo in:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    /Developer/qt/examples/demo&lt;/span&gt;&lt;br /&gt;from Finder&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Getting QtRuby running&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Get a copy of QtRuby by going to&lt;br /&gt;&lt;a href="http://rubyforge.org/projects/korundum"&gt;http://rubyforge.org/projects/korundum&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;on that page, there is a Download link for the package qtruby (version 1.0.13).&lt;br /&gt;&lt;br /&gt;Clicking that takes you to the download page.  Scroll down to the section for qtruby and then look for&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;qtruby-1.0.13.tgz&lt;/span&gt;&lt;br /&gt;and click on it to download&lt;br /&gt;&lt;br /&gt;You should see a "qtruby-1.0.13.tgz" file on your desktop.&lt;br /&gt;Double click that &amp; it will expand and create a folder cladded "qtruby-1.0.13"&lt;br /&gt;&lt;br /&gt;Delete the .tgz file&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;--NOTE: I've been told that later versions of the qtruby package have fixed this issue, so you may not need to do this&lt;/span&gt;&lt;br /&gt;go to the&lt;br /&gt; &lt;span style="font-family:courier new;"&gt;smoke/qt&lt;/span&gt;&lt;br /&gt;directory and edit the Makefile.in and change version info on line 233 from&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;3:4:92&lt;/span&gt;&lt;br /&gt;to&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;3:4:0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After the edit, the line should read:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;libsmokeqt_la_LDFLAGS = -version-info 3:4:92 -no-undefined $(KDE_NO_UNDEFINED) \&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;$(all_libraries) $(GLINC)   &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;also in the&lt;br /&gt;   &lt;span style="font-family:courier new;"&gt;smoke/qt &lt;/span&gt;&lt;br /&gt;directory, edit&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;smokeqt.pro&lt;/span&gt;&lt;br /&gt;and change DESTDIR to&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/usr/local/lib&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;finally, go to&lt;br /&gt;   &lt;span style="font-family:courier new;"&gt;../../qtruby/rubylib/designer/rbuic/&lt;/span&gt;&lt;br /&gt;and edit&lt;br /&gt;   &lt;span style="font-family:courier new;"&gt;rbuic.pro&lt;/span&gt;&lt;br /&gt;changing DESTDIR to&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/usr/local/bin&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;now go back to the top level of QtRuby-1.0.13&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;cd ~/Desktop/qtruby-1.0.13/&lt;/span&gt;&lt;br /&gt;and do a configure&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  ./configure '--with-qt-dir=/Developer/qt'  '--enable-mac'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;now you're ready to create the makefile&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    cd smoke/qt&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    perl generate.pl&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;stay in the current directory (smoke/qt) and now finish creating the makefile using Trolltech's qmake&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    $QTDIR/qmake/qmake -makefile&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;At this point, you're ready to build and install.  These are both done when you do a make, but the install part will fail unless you sudo the make so it runs as administrator&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    sudo make&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Next we need to build the 'Qt' extension&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   cd ~/Desktop/qtruby-1.0.13/qtruby/rubylib/qtruby&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   ruby extconf.rb --with-qt-dir=/Developer/qt --with-smoke-dir=/usr/local --with-smoke-include=../../../smoke&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(note for those who are flipping back and forth between this and the &lt;span style="font-family:georgia;"&gt;install&lt;/span&gt; files that came with the software: because we installed smoke into /usr/local we had to refer to that in the -with-smoke-dir parameter)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;make&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   sudo make install&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;now build the rbuic&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   cd ../designer/rbuic/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   $QTDIR/qmake/qmake -makefile&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Build the 'qui' QWidgetFactory extension&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   cd ../uilib&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   ruby extconf.rb --with-qtruby-include=../../qtruby --with-qt-dir=/Developer/qt&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   make&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   sudo make install&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ok ... QtRuby should now be installed, so lets test it&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Test #1 -- Can Ruby find Qt?&lt;/span&gt;&lt;br /&gt;in a terminal window, start irb&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;irb&lt;/span&gt;&lt;br /&gt;and try to load Qt&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;require 'Qt'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;this should return true&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   =&gt; true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;if you get an error instead (dyld: NSLinkModule() error), then you need to check you DYLD_LIBRARY_PATH and make sure it contains "Developer/qt/lib"&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   env | grep DYLD_LIBRARY_PATH&lt;/span&gt;&lt;span class="" style="display: block;" id="formatbar_CreateLink" title="Link" onmouseover="ButtonHoverOn(this);" onmouseout="ButtonHoverOff(this);" onmouseup="" onmousedown="CheckFormatting(event);FormatbarButton('richeditorframe', this, 8);ButtonMouseDown(this);"&gt;&lt;/span&gt;&lt;br /&gt;if you don't see the that present, go back and look at your .bash_profile&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Test #2 -- Is Ruby getting and processing events&lt;/span&gt;&lt;br /&gt;this test is important because in some cases (for example, you replaced the version of ruby that came with Tiger with one that you built yourself from the 1.8.4 src), you default copy of ruby won't be setup to process events on the Mac correctly and you'll need to create a "rubyw" that can do so.&lt;br /&gt;&lt;br /&gt;Copy and paste the following ruby code (taken verbatim from Caleb's &lt;a href="http://www.pragmaticprogrammer.com/titles/ctrubyqt/index.html"&gt;book&lt;/a&gt;) into a file file called test2.rb:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;require 'Qt'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;class MyWidget &lt;&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; slots 'button_was_clicked()'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; def initialize(parent=nil)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   super(parent)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   @label = Qt::Label.new(self)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   @button = Qt::PushButton.new(self)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   @layout = Qt::VBoxLayout.new(self)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   @layout.addWidget(@label)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   @layout.addWidget(@button)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   @clicked_times = 0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   @label.setText("The button has been clicked #{@clicked_times} times")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   @button.setText("MyButton")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   connect(@button,SIGNAL('clicked()'),self,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;           SLOT('button_was_clicked()'))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; def button_was_clicked&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   @clicked_times += 1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   @label.setText("The button has been clicked #{@clicked_times} times")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; end&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;a = Qt::Application.new(ARGV)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;mw = MyWidget.new&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;a.setMainWidget(mw)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;mw.show&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;a.exec&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;run this by executing the following in terminal:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ruby $PWD/test2.rb&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;A small window with a label ("The button has been clicked 0 times") and a button should appear.  Clicking the button should change the text of the label to indicate how many times you've clicked.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;If this works, you're good to go.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;If what happens instead is that the button appears to push down, but never pop up and the text never changes, chances are your copy of ruby isn't bound to the correct Mac resource fork.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;Run the following:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   ruby=`which ruby`&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   rubyw=${ruby}w&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   sudo cp $ruby $rubyw&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   sudo /Developer/Tools/Rez -t APPL Carbon.r -o $rubyw&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;and then try again, using the rubyw (not ruby) executable:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   rubyw $PWD/test2.rb&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;Hopefully that will work.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;I'm not 100% sure about whether you need to actually keep rubyw as a separate executable.  I think that you actually could Rez you base ruby executable and the you'd have one copy of the language that could run standard ruby and handle Mac events.  I think this is what was done with the default copy that shipped with Tiger.  However, I don't know enough of the mac internals to be certain about this, so try it at your own risk (at least save a copy of ruby before overwriting it with rubyw :-))&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-3540990464421333091?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/3540990464421333091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=3540990464421333091' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/3540990464421333091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/3540990464421333091'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2007/01/installing-qtruby-on-mac-osx.html' title='Installing QTRuby on Mac OSX'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-113864581781573934</id><published>2006-01-30T10:23:00.000-08:00</published><updated>2006-01-30T10:47:31.343-08:00</updated><title type='text'>Preserving your data when changing your schema</title><content type='html'>I've been working with rails in an agile model ... build something, get it working &amp; tested, move on to the next thing. As a result, my underlying schema is continually evolving. Mostly that's in the form of additional tables being added, but sometimes it's changes to existing tables to add new fields, etc.&lt;br /&gt;&lt;br /&gt;When I make these changes, I don't want to lose the data I've already got loaded into the old tables. I also wanted to have stand alone files/scripts that could build and populate my database from scratch so I could do clean builds. As a result, I wasn't comfortable with just going into the database's interactive console and doing &lt;pre&gt;CREATE TABLE&lt;/pre&gt; and &lt;pre&gt;ALTER TABLE&lt;/pre&gt;My understanding is that Rail's migrations are a great way to do this, but with so many things to learn, I haven't gotten to them yet.&lt;br /&gt;&lt;br /&gt;On my development machine (Mac G5 with Rails 1.0 and MySQL 4.x), I've created the following short aliases to dump the current database contents, build a clean db from my db/create.sql script, and then reload my data:&lt;br /&gt;&lt;pre&gt;imac20:~/Technical/ruby/rails/myapp steven$ db_dump&lt;br /&gt;imac20:~/Technical/ruby/rails/myapp steven$ db_build&lt;br /&gt;imac20:~/Technical/ruby/rails/myapp steven$ db_reload&lt;br /&gt;&lt;/pre&gt;These are based on the aliases being defined in my .bashrc file:&lt;br /&gt;&lt;pre&gt;alias db_dump='mysqldump -u app1 -ppw1 -t -c myapp_development &gt; db/obelisk.dump'&lt;br /&gt;alias db_build='mysql -u app1 -ppw1 myapp_development &lt; db_reload="'mysql"&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;if you try to use these, you'll need to replace "app1" with your mysql account name, "pw1" with your password, and "myapp_development" with the name of the database you are using for development.&lt;br /&gt;&lt;br /&gt;the -t and -c flags on mysqldump do the following:&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;-t&lt;/span&gt; --&gt; stops the dump from including table creation information. This is important because all the tables are created by db_build in step 2. If you don't have the -t option when you do the dump, you'll run into problems in step 3 (db_reload) if you're trying to import data back into a table where a column has been added.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;-c&lt;/span&gt; --&gt; forces the dump to create complete insert statements (with column names). Again this is important if the change you've made to your create.sql includes changes to the columns of an existing table.&lt;br /&gt;&lt;br /&gt;One more thing... in order to get OSX to load the aliases in your ~/.bashrc file, you need to have the following in your ~/.bash_profile &lt;pre&gt;if [ -f ~/.bashrc ]; then source ~/.bashrc; fi&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The format of create.sql follows the advice from &lt;a href="http://pragmaticprogrammer.com/titles/rails/index.html"&gt;Agile Web Development with Rails.&lt;/a&gt;&lt;br /&gt;&lt;pre&gt;Drop Table if exists my_table;&lt;br /&gt;Create Table my_table(&lt;br /&gt;...columns go here...&lt;br /&gt;primary key(id)&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-113864581781573934?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/113864581781573934/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=113864581781573934' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/113864581781573934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/113864581781573934'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2006/01/preserving-your-data-when-changing.html' title='Preserving your data when changing your schema'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21714662.post-113864526404314859</id><published>2006-01-30T10:19:00.000-08:00</published><updated>2006-01-30T10:21:04.050-08:00</updated><title type='text'>Why another rails blog?</title><content type='html'>For about the last month, I've been building business applications with Ruby on Rails and loving it.  In the course of that time, I've hit a number of road blocks and had to figure out how to get around them.  I thought it might be save other new rails developers to see these problems/solutions, so I started this blog.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21714662-113864526404314859?l=stevechanin.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://stevechanin.blogspot.com/feeds/113864526404314859/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21714662&amp;postID=113864526404314859' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/113864526404314859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21714662/posts/default/113864526404314859'/><link rel='alternate' type='text/html' href='http://stevechanin.blogspot.com/2006/01/why-another-rails-blog.html' title='Why another rails blog?'/><author><name>Steve</name><uri>http://www.blogger.com/profile/05578730862896293134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_4pVxSWHEpnw/TROj2y09eaI/AAAAAAAAAAM/rTz2RQDbobU/S220/Photo%2B3.jpg'/></author><thr:total>0</thr:total></entry></feed>
