tag:www.katrinaowen.com,2008:/posts ~/scratch 2011-02-03T20:21:28Z Enki Katrina Owen katrina.owen@gmail..com tag:www.katrinaowen.com,2008:Post/11 2011-02-04T04:21:00Z 2011-02-03T20:21:28Z Schema loading for tests in rails <p>I&#8217;m reading The Rails 3 Way by Obie Fernandez, and it says</p> <blockquote> <p>Every time you run tests, Rails dumps the schema of your development database and copies it to the test database using an autogenerated schema.rb script.</p> </blockquote> <p>In my experience this isn&#8217;t quite what happens. From what I&#8217;ve observed:</p> <ul> <li><code>schema.rb</code> gets generated when you call <code>rake db:migrate</code></li> <li>the schema gets loaded from <code>schema.rb</code> to your test database when you call <code>rake db:test:prepare</code></li> <li>when you run tests, the calls to the database inside each of the tests are run within a transaction that gets rolled back at the end of the test</li> </ul> <p>In practice, you could therefore load seed data into your test database after calling <code>rake db:test:prepare</code> and you wouldn&#8217;t lose this every time you run your tests.</p> <pre>namespace :db do namespace :test do desc "Init bare bones test data" task :seed_db do # your seed data here end end end</pre> <pre>Rake::Task["db:test:prepare"].enhance do Rake::Task["db:test:seed_db"].invoke end</pre> <p>Is this a good idea? Well, It depends. I&#8217;m working on one project where it is extremely helpful. Perhaps when we&#8217;ve gotten things refactored a bit it won&#8217;t be necessary anymore.</p> tag:www.katrinaowen.com,2008:Post/9 2011-01-29T08:39:13Z 2011-01-29T08:37:30Z Rails 3 Scopes: With great power comes great responsibility. <p>I wrote one of the worst bugs of my career (so far) the other day.</p> <p>The long and short of it is this:<br /> ActiveRecord::Relation may behave like an array in many ways, but it&#8217;s not an array. If you are doing something which is completely harmless to an array, but could be potentially destructive to an active record relation, make sure what you have <em>really</em> is an array.</p> <h2>It goes like this</h2> <p>Create a fresh rails3 project, and set it up to use rspec.</p> <pre>$ rails new todo -T # Gemfile source 'http://rubygems.org' gem 'rails', '~&gt; 3.0' gem 'sqlite3-ruby', :require =&gt; 'sqlite3' gem 'rspec-rails', '~&gt; 2.4'</pre> <pre>rails g rspec:install</pre> <p>Create a simple model.</p> <pre>rails g migration create_tasks</pre> <pre>class CreateTasks &lt; ActiveRecord::Migration def self.up create_table :tasks do |t| t.column :description, :text t.column :done, :boolean, :default =&gt; false t.timestamps end end</pre> <pre> def self.down drop_table :tasks end end</pre> <pre>rake db:migrate &amp;&amp; rake db:test:prepare</pre> <p>Add a scope</p> <pre>class Task &lt; ActiveRecord::Base scope :done, where('done = ?', true) end</pre> <p>This is where it gets interesting.</p> <pre>require 'spec_helper'</pre> <pre>describe Task do it "cleanly extracts from array" do trucs = {:des =&gt; :trucs} machin = {:un =&gt; :machin} bidule = {:une =&gt; :bidule}</pre> <pre> stuff = [trucs, machin, bidule]</pre> <pre> extracted = stuff.delete(machin) extracted.should == machin stuff.should_not include(machin) end</pre> <pre> context "active record relation" do it "extracts cleanly" do jump = Task.create(:description =&gt; 'jump') run = Task.create(:description =&gt; 'run') walk = Task.create(:description =&gt; 'walk')</pre> <pre> activities = Task.all # activities.class == Array</pre> <pre> extracted = activities.delete(run) extracted.should == run activities.should_not include(run)</pre> <pre> Task.all.should include(run) end</pre> <pre> it "doesn't. Sneaky bastard" do jump = Task.create(:description =&gt; 'jump', :done =&gt; true) run = Task.create(:description =&gt; 'run', :done =&gt; true) walk = Task.create(:description =&gt; 'walk', :done =&gt; true)</pre> <pre> activities = Task.done # activities.class == ActiveRecord::Relation</pre> <pre> extracted = activities.delete(run)</pre> <pre> Task.all.should include(run)</pre> <pre> # fails # incidentally, also fails on these: # popped.should == run # activities.should_not include(run) end end end</pre> <p>To quote the log:</p> <blockquote> <p><span class="caps">AREL</span> (0.2ms) <span class="caps">DELETE</span> <span class="caps">FROM</span> &#8220;tasks&#8221; <span class="caps">WHERE</span> (done = &#8216;t&#8217;) <span class="caps">AND</span> (&#8220;tasks&#8221;.&#8220;id&#8221; = 2)</p> </blockquote> <p>Yeah. Potentially really not good.</p> tag:www.katrinaowen.com,2008:Post/10 2011-01-13T04:00:00Z 2011-01-30T13:30:11Z PostgreSQL template tables and rake db:test:prepare <p>I recently overcame the final hurdle to getting rspec hooked up within this legacy project that I&#8217;m working on (legacy in the sense that it has no tests, and is in production, and works).</p> <p>There were three levels of fail with respect to running <code>rake db:test:prepare</code></p> <h2>Fail #1: Configuration</h2> <p>The database configuration file had the test environment looking at the same database as development. The first time I ran <code>rake db:test:prepare</code> it dropped my development database. Usually this isn&#8217;t such a huge disaster, but in this case we&#8217;re using a slightly sanitized version of the production database. It takes 45 minutes to scp it down from the backup server, and 4+ hours to load.</p> <p>The solution, of course, was to change this:</p> <pre>test: adapter: postgresql database: legacyproject_development</pre> <p>to this:</p> <pre>test: adapter: postgresql database: legacyproject_test</pre> <h2>Fail #2: Bug in Schema Dumper</h2> <p>This project happens to be using a homegrown plugin for PostGIS (because at the time we needed one there were no other available options). Since we&#8217;ve never needed to actually load the database from the schema, nobody had noticed that the schema definition of geometry tables were lacking the parameter for the <span class="caps">SRID</span>.</p> <pre>wrong number of arguments (4 for 5)</pre> <p>Fixing the custom schema dumper for the geometry tables fixed this issue.</p> <h2>Fail #3: Missing PostGIS Functions and Tables</h2> <p>The production and development databases had been set up manually to include the PostGIS goodies. <code>rake db:test:prepare</code> was now correctly creating the test database based on the schema, but was lacking everything PostGIS. Three options immediately came to mind:</p> <ul> <li>write a task that manually loaded all the postGIS stuff and have it run prior to the <code>rake db:test:prepare</code> task <em>(uhm, no thanks)</em>.</li> <li>add the PostGIS stuff to the default postgresql template table, template1 <em>(I&#8217;d rather not)</em>.</li> <li>create a special PostGIS template table <em>(yes, please)</em>.</li> </ul> <p>So I did:</p> <pre>psql -d postgres -U postgres CREATE DATABASE template_postgis WITH TEMPLATE=template1 ENCODING='UTF8'; \c template_postgis; CREATE LANGUAGE plpgsql; \i /opt/local/share/postgresql90/contrib/postgis-1.5/postgis.sql \i /opt/local/share/postgresql90/contrib/postgis-1.5/spatial_ref_sys.sql UPDATE pg_database SET datistemplate = TRUE WHERE datname = 'template_postgis'; GRANT ALL ON geometry_columns TO PUBLIC; GRANT ALL ON spatial_ref_sys TO PUBLIC; </pre> <p>And then all I needed to do define the database config so that it used this template instead of template1 when created the test database.</p> <pre>test: adapter: postgresql template: template_postgis database: legacyproject_test</pre> <p>Ah, right. Not so simple. It would seem that noone has needed this config options, so rails doesn&#8217;t recognize the template option.</p> <p>So we submitted a patch to rails. <a href="https://github.com/kowen/rails/commit/1050dc3f964ced1fa73009826109c40b507cfb47">Smallest patch in the history of rails</a> probably, at less than 30 characters</p> <p><strong>#win</strong></p> tag:www.katrinaowen.com,2008:Post/8 2011-01-07T09:04:09Z 2011-01-07T09:04:09Z A (silly) PostgreSQL gotcha <p>As I was setting up my latest project in Rails 3 with PostgreSQL, Cucumber, RSpec and various other goodies, I got this error when running <code>rake db:migrate</code>:</p> <pre>PGError: ERROR: permission denied for relation schema_migrations SELECT version FROM schema_migrations</pre> <p>I took a quick look in my config/database.yml</p> <p>And saw the following ridiculousness:</p> <pre>development: adapter: postgresql encoding: unicode database: myproject_development host: localhost pool: 5 username: password: productionpassword</pre> <p>Updating username to myproject and password to be blank did the trick.</p> tag:www.katrinaowen.com,2008:Post/7 2011-01-05T08:55:54Z 2011-01-05T08:54:59Z Using PostgreSQL with Rails 3, Cucumber & RSpec <p>One thing that tripped me up when trying to set up a new project using PostgreSQL rather than sqlite3, is that when running <code>rake db:test:prepare</code> I got the error message:</p> <pre>/path/to/rake:19:in `&lt;main&gt;' Couldn't create database for {"adapter"=&gt;"postgresql", "encoding"=&gt;"unicode", "database"=&gt;"myproject_test", "host"=&gt;"localhost", "pool"=&gt;5, "username"=&gt;"moi", "password"=&gt;nil, "min_messages"=&gt;"WARNING"} rake aborted! FATAL: database "test" does not exist</pre> <p>This despite having just run <code>createdb -O moi test</code></p> <p>I recreated the database, checked that it was, in fact, there (<code>psql myproject_test</code>, and ran the rake command again. Boom. Same error message.</p> <p>Turns out the user &#8220;moi&#8221; was allowed to drop databases, but not create them.</p> <pre>psql myproject_development; ALTER USER moi CREATEDB; \q</pre> <p>Et voila.</p> tag:www.katrinaowen.com,2008:Post/6 2010-12-28T07:54:00Z 2010-12-27T21:55:57Z Lazybones: Skeleton Rails3 App <p>I&#8217;ve set myself a 30 day challenge for the month of January. Nevermind that January has 31 days.</p> <p><em>Every morning, I&#8217;m going to get up an hour early (yes, weekends included) and practice programming.</em></p> <p>This is different from programming at work. For one, I don&#8217;t need to deliver anything. I basically want to be able to do some deliberate practice on <span class="caps">TDD</span>/<span class="caps">BDD</span> and refactoring, as well as explore some gems that I&#8217;m unfamiliar with.</p> <p>I have a couple of projects that I can use for this. One is OverkillCMS:<br /> <a href="http://github.com/kowen/overkill">git://github.com/kowen/overkill.git</a></p> <p>This is a simple <span class="caps">CMS</span> for a friend of mine which I&#8217;m making simply to practice full <span class="caps">TDD</span>/<span class="caps">BDD</span> using rspec and cucumber. That, and because her current website requires her to edit html and css, and she&#8217;s not a programmer.</p> <p>Another is Carbon Dating &#8211; An Open-Source Ruby on Rails Dating App<br /> <a href="http://github.com/kowen/c14">git://github.com/kowen/c14.git</a></p> <p>This one is also inspired by some friends of mine. They&#8217;re running a tiny niche dating site that uses some of the ugliest <span class="caps">PHP</span> code you will ever see. It&#8217;s an embarrassment to cowboy coders everywhere.</p> <p>In preparation for these two projects, I went ahead and found out how to set up a rails 3 project per my own preferences (rspec, cucumber, jasmine, haml, sass, compass, watchr, metric_fu) and documented it here, along with some convenience files:</p> <p><a href="http://github.com/kowen/lazybones">git://github.com/kowen/lazybones.git</a></p> tag:www.katrinaowen.com,2008:Post/5 2010-12-18T11:32:03Z 2010-12-18T11:31:30Z Zeo: Hacking Sleep <p>I purchased a zeo.</p> <p>I received it yesterday, have tried it once, and so far I&#8217;m impressed. It&#8217;ll be exciting to see how much data I can get out of it.</p> <p>It was able to report:</p> <ul> <li>how long it took me to fall asleep (33 minutes)</li> <li>how long I slept, total (10 hours, 25 minutes)</li> <li>how many times I woke up during the night (6. Ouch. I only remember 3 of them.)</li> <li>how much deep, light, and <span class="caps">REM</span> sleep I got (plenty!)</li> </ul> <p>The headband was comfortable and non-disruptive. I toss a bit, and slept on my sides and my stomach, and the headband didn&#8217;t budge.</p> <p>My ZQ score was 114. Sky high, according to the pamphlet they included in the package. Apparently in my age bracket the average is around 80.</p> <p>Interestingly, when I woke up, my subjective judgement was that I had slept &#8220;okay&#8221;.</p> tag:www.katrinaowen.com,2008:Post/4 2010-12-17T20:27:00Z 2010-12-17T12:20:30Z Encoding issues: cucumber <p>In my standalone test runner which uses ruby 1.9.2, cucumber driving firewatir, and using rspec matchers I have a test that looks like this:</p> <pre><code>Scenario: Single logout flash Given I am logged in with "username"/"password" When I log out Then I should see "Du er nå logget ut"</code></pre> <p>That last bit is in Norwegian. The project this code tests has support for two Norwegian written languages, and English (sort of). Actually, let&#8217;s not go there.</p> <p>The browser is set up like this:</p> <pre><code>Watir::Browser.default = "firefox"</code></pre> <pre><code>def browser @browser ||= Watir::Browser.new end</code></pre> <p>The test should be passing, but I get the following error on the line with the Norwegian text in it.</p> <pre><code>incompatible character encodings: ASCII-8BIT and UTF-8 (Encoding::CompatibilityError)</code></pre> <p>Tthe step definition for the failing step is:</p> <pre><code>Then /^I should see "([^"]*)"$/ do |term| browser.text.should include(term) end</code></pre> <p><span class="caps">ASCII</span>-8BIT isn&#8217;t really an encoding, as far as I can tell. It&#8217;s unencoded bytes (and is therefore aliased to <span class="caps">BINARY</span>).</p> <p>There are a few places this can blow up, I think.<br /> 1. The file itself could be encoded wrong.<br /> 2. The regex could be having trouble with utf-8, so the <code>term</code> could be unencoded<br /> 3. the <code>browser.text</code> could be unencoded.</p> <p>My first reaction was to add <code># encoding: utf-8</code><br /> to the top of each of my files in the project. I should have thought of it earlier &#8212; I&#8217;ve been having to do this on a lot of projects with Norwegian output lately. Unfortunately that didn&#8217;t change the output for the failing scenario.</p> <p>Next I dug into at the documentation for the <a href="http://www.ruby-doc.org/core-1.9/classes/Encoding.html">ruby encoding class</a> and tried setting default internal and external encoding in the <code>env.rb</code> file:</p> <pre><code>Encoding.default_internal = Encoding::UTF_8 Encoding.default_external = Encoding::UTF_8</code></pre> <p>No dice. The output remained the same.</p> <p>Next, I tried forcing the regex to deal with utf-8 properly (<code>/matcher/u</code>)</p> <pre><code>Then /^I should see "([^"]*)"$/u do |term|</code></pre> <p>The output was unchanged.</p> <p>Reluctantly, I tried what feels like a fairly dirty hack:</p> <pre><code>browser.text.force_encoding('utf-8').should include(term)</code></pre> <p>This worked.</p> <p>So it seems like FireWatir&#8217;s text comes back unencoded.</p> tag:www.katrinaowen.com,2008:Post/3 2010-12-13T16:32:06Z 2010-12-13T16:26:56Z Repeat after me: hypothesis <blockquote> <p><em>I have a theory that a butterfly is actually a pegasus that flew too high and died of asphyxiation and then was reborn as a caterpillar.</em></p> </blockquote> <p>In short, if it is &#8220;just a theory&#8221;, then it&#8217;s not a theory at all. It might be a hypothesis, or a hunch, or a guess, or sometimes even a conjecture. But certainly not a theory.</p> <p>And, for the record, evolution is /not/ &#8220;just a theory&#8221;. It&#8217;s well-substantiated, well-supported, and well-documented, explaining scientific observations. I.e. <strong>a theory</strong>.</p> <p>Just sayin&#8217;.</p> tag:www.katrinaowen.com,2008:Post/2 2010-12-08T16:23:04Z 2010-12-08T16:21:07Z Order of Callbacks/Validations on Active Record <p>Every once in a while I find myself wondering about this. So here it is, for the record:</p> <p>The order of callbacks and validations on a rails active record model is</p> <p>1. before_validation<br /> 2. before_validation, :on =&gt; :create<br /> 3. after_validation<br /> 4. after_validation, :on =&gt; :create<br /> 5. before_save<br /> 6. before_create<br /> 7. after_create<br /> 8. after_save</p> <p>ActiveRecord wraps this whole thing in a transaction, so if anything anywhere in this chain fails, the whole thing will be rolled back.</p> <p>Good to know!</p> tag:www.katrinaowen.com,2008:Post/1 2010-12-07T20:00:00Z 2010-12-08T07:43:17Z Survival of the fittest <p>It seems like every time I hear the phrase <em>survival of the fittest</em> it&#8217;s used to mean something like <em>the one with the most muscle will win when you duke it out</em>.</p> <p>Quick reminder: In biology, being <em>fit</em> isn&#8217;t about being physically powerful. It&#8217;s about having offspring that survive long enough to have offspring.</p> <p>The phrase &#8220;survival of the fittest&#8221; is almost redundant, in that it basically states that the genes that survive are the ones that get passed on.</p> <p>Traditionally this is all about luck and randomness. Humans have recently (in evolutionary terms) added inventiveness into the mix.</p>