<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>No Pugs : Category typo, everything about typo</title>
    <link>/category/typo.rss</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>they're evil</description>
    <item>
      <title>Unable to login after upgrade from typo 5.1.3 to 5.3 via git</title>
      <description>&lt;p&gt;Upgrading via a git merge might not be the best way of upgrading typo.  The safest way is probably to follow the instructions in the UPGRADE file.  However, I have a few modifications I've made to Typo that I'd like to preserve.&lt;/p&gt;

&lt;p&gt;So I went ahead and merged 5_3_0 with my 5.1.3 branch and ran a db:migrate&lt;/p&gt;

&lt;p&gt;I couldn't log in anymore.  It turns out a "status" column is added to the users table in a migration, and in the same migration, each existing user's status is set to "active"&lt;/p&gt;

&lt;p&gt;The problem is that after a db:migrate, the status column was still NULL.  What happens is that it works if you run 1 migration at a time.  But if you run the migration that adds and sets the status column to "active" in the same rake invocation that has already accessed the User class, it will already have the old columns loaded into it and will not think the "status" column even exists.&lt;/p&gt;

&lt;p&gt;To fix it, you need to issue a User.reset_column_information after adding the column.  &lt;/p&gt;

&lt;p&gt;This column is not the only problem column, the "text_filter_id" and "editor" column also failed to update.&lt;/p&gt;

&lt;p&gt;Below is a quick patch I made from my typo repository.  I only went back to the migrations I was missing between 5.1.3 and 5.3 and made sure any model classes that were used had "reset_column_information" called before using.  If you are going to attempt upgrading your typo blog via a git merge/pull, this patch might be useful.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://nopugs.com/files/0001-Changed-some-recent-migrations-to-call.patch"&gt;0001-Changed-some-recent-migrations-to-call.patch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A note about an oddity I ran into when running these migrations in a production environment: You'll need to set config.cache_classes in config/environments/production.rb to false while running the migrations, otherwise it might try to preload information about classes whose tables don't yet exist.  I'm not exactly sure why this happens, I've never had this problem in the past.&lt;/p&gt;

&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-5048333526809695";
/* 468x60, created 12/3/09 */
google_ad_slot = "0558736130";
google_ad_width = 468;
google_ad_height = 60;
//--&gt;
&lt;/script&gt;

&lt;script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;</description>
      <pubDate>Wed, 02 Dec 2009 22:08:00 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:d0e57704-bf80-4dd0-ae43-d5689b41849d</guid>
      <author>azimux@gmail.com (miles)</author>
      <comments>http://nopugs.com/2009/12/02/unable-to-login-after-upgrade-from-typo-5-1-3-to-5-3-via-git#comments</comments>
      <category>Ruby on Rails</category>
      <category>typo</category>
      <enclosure url="http://nopugs.com/files/0001-Changed-some-recent-migrations-to-call.patch" type="text/plain" length="4560"/>
      <trackback:ping>http://nopugs.com/trackbacks?article_id=26</trackback:ping>
      <link>http://nopugs.com/2009/12/02/unable-to-login-after-upgrade-from-typo-5-1-3-to-5-3-via-git</link>
    </item>
    <item>
      <title>How to migrate typo from mysql to postgresql</title>
      <description>&lt;p&gt;I almost always use postgresql when working on a rails application.  I won&amp;#8217;t list all the little reasons why, but a major reason is for  transactional DDL statements, which means when I run a migration that fails, I don&amp;#8217;t have to then go run a bunch of cleanup queries to get my database back to how it was before the migration was ran.&lt;/p&gt;

&lt;p&gt;When I was setting up this instance of typo, I decided I&amp;#8217;d go ahead and go with mysql since I didn&amp;#8217;t plan to hack on typo very much.  Long story short: I decided to migrate from mysql to postgresql.  This howto was done with mysql 5.0.70, postgresql 8.3.5, and typo 5.1.3  It probably will work with any mysql 5+ and postgresql 8+.&lt;/p&gt;

&lt;p&gt;In case anybody else out there might be interested in doing likewise, here&amp;#8217;s how I did it.  These steps will be for a production database, but the changes required for doing it to a development database should be obvious.&lt;/p&gt;

&lt;h2&gt;Step 0: Backup your data&lt;/h2&gt;

&lt;p&gt;You don&amp;#8217;t really need to be told this, do you?&lt;/p&gt;

&lt;h2&gt;Step 1: Dump the data from mysql&lt;/h2&gt;

&lt;p&gt;run the following to dump the data.  &lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;
mysqldump --compatible=postgresql --no-create-info -u root -p --skip-extended-insert --complete-insert --skip-opt typo &gt; typo.dump 

&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We are only dumping the data, hence the &amp;#8211;no-create-info option.&lt;/p&gt;

&lt;h2&gt;Step 2: Create your postgresql database&lt;/h2&gt;

&lt;p&gt;You can do this however you see fit.  I&amp;#8217;ve included how I do it in case it&amp;#8217;s useful:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;&lt;span class="r"&gt;CREATE&lt;/span&gt; &lt;span class=""&gt;USER&lt;/span&gt; &lt;span class=""&gt;typo_prod&lt;/span&gt;;
&lt;span class="r"&gt;CREATE&lt;/span&gt; &lt;span class=""&gt;DATABASE&lt;/span&gt; &lt;span class=""&gt;typo_prod&lt;/span&gt; &lt;span class=""&gt;OWNER&lt;/span&gt; &lt;span class=""&gt;typo_prod&lt;/span&gt; &lt;span class=""&gt;ENCODING&lt;/span&gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;;

&lt;span class="er"&gt;\&lt;/span&gt;&lt;span class=""&gt;password&lt;/span&gt; &lt;span class=""&gt;typo_prod&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and enter the password you wish to use.&lt;/p&gt;

&lt;h2&gt;Step 3: Change your database.yml to use your new postgresql database &lt;/h2&gt;

&lt;p&gt;Again, do this however you want.  Here&amp;#8217;s my database.yml with passwords omitted:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;defaults: &amp;amp;defaults
  database: typo
  adapter: postgresql
  encoding: utf8
  host: localhost
  password: 

development:
  username: typo_dev
  database: typo_dev
  &amp;lt;&amp;lt;: *defaults

test:
  username: typo_test
  database: typo_test
  &amp;lt;&amp;lt;: *defaults

production:
  username: typo_prod
  database: typo_prod
  password: 
  host: salmon
  &amp;lt;&amp;lt;: *defaults
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Step 4: Create the schema in your new database&lt;/h2&gt;

&lt;p&gt;To do this we&amp;#8217;ll run the db:migrate rake task&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;RAILS_ENV="production" rake db:migrate&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Step 5: Fire up a rails console to fix stuff&lt;/h2&gt;

&lt;p&gt;Now we need to fire up a rails console to do a lot of necessary cleanup work before we can import our data&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;ruby script/console production&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once it&amp;#8217;s ready to go, type (or more practically, copy pasta)&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;conn = &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;.connection&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;#8217;ll need this for a lot of the commands we have yet to run.  You&amp;#8217;ll keep this console open for the remainder of this howto.  Any ruby code you see in this document will go into this console.&lt;/p&gt;

&lt;h2&gt;Step 6: Remove data created during the migrations&lt;/h2&gt;

&lt;p&gt;The typo migrations automatically add some default data, like some default pages/articles/blog.  All of the data we want is in the dump we created earlier.  Let&amp;#8217;s delete all this stuff that&amp;#8217;s in the way&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;conn.tables.each &lt;span class="r"&gt;do&lt;/span&gt; |table|
  conn.execute &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;delete from &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;table&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Step 7: Temporarily change boolean columns to integers&lt;/h2&gt;

&lt;p&gt;mysqldump dumps it&amp;#8217;s booleans as 0/1.  These are interpreted by postgres as integers.  It will not automatically cast these into booleans just because the column is boolean (I&amp;#8217;m not sure why.)  It&amp;#8217;s too time consuming to go add casts to all of these 0/1&amp;#8217;s, and a regular expression to use with sed would be far too complex to bother with since not all 1&amp;#8217;s and 0&amp;#8217;s in the dump correspond to boolean data.&lt;/p&gt;

&lt;p&gt;So, we will &lt;em&gt;temporarily&lt;/em&gt; change the boolean columns in our shiny new database to integers.  Before we do this, we need to &lt;em&gt;temporarily&lt;/em&gt; drop the defaults for these boolean columns because there won&amp;#8217;t be an implicit cast from false/true to 0/1.&lt;/p&gt;

&lt;p&gt;This code will build a couple of hashes to store which columns are booleans and what the defaults are.  &lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;bools = {}
defaults = {}


conn.tables.each &lt;span class="r"&gt;do&lt;/span&gt; |table|
  conn.columns(table).each &lt;span class="r"&gt;do&lt;/span&gt; |col|
    &lt;span class="r"&gt;if&lt;/span&gt; col.type.to_s == &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;boolean&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
      (bools[table] ||= []) &amp;lt;&amp;lt; col.name
      (defaults[table] ||= {})[col.name] = col.default &lt;span class="r"&gt;if&lt;/span&gt; !col.default.nil?
    &lt;span class="r"&gt;end&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;here&amp;#8217;s the value of &lt;strong&gt;bools&lt;/strong&gt; and &lt;strong&gt;defaults&lt;/strong&gt; in my console after the above code:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;&lt;span class="c"&gt;#bools&lt;/span&gt;
{&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;resources&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;itunes_metadata&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;itunes_explicit&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;], &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;contents&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, 
&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;allow_pings&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;allow_comments&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;], &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;notify_via_email&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, 
&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;notify_on_new_articles&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;notify_on_comments&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;notify_watch_my_articles&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, 
&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;notify_via_jabber&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;], &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;feedback&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;status_confirmed&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;], 
&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;categorizations&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;is_primary&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]}
&lt;span class="c"&gt;#defaults&lt;/span&gt;
{&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;contents&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;{&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;&lt;span class="pc"&gt;false&lt;/span&gt;}, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;feedback&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;{&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;&lt;span class="pc"&gt;false&lt;/span&gt;}}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let&amp;#8217;s now temporarily drop the defaults&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;defaults.each_pair &lt;span class="r"&gt;do&lt;/span&gt; |table,cols|
  cols.each_key &lt;span class="r"&gt;do&lt;/span&gt; |col|
    conn.execute &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;alter table &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;table&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; alter column &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;col&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; DROP DEFAULT&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;      
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now let&amp;#8217;s alter the column types for the columns in &lt;strong&gt;bools&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ll use a closure to run the alter statements, so that we can use it again later to alter them back to booleans.&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;change_to_type = proc {|to_type|
  bools.each_pair &lt;span class="r"&gt;do&lt;/span&gt; |table, cols|
    cols.each &lt;span class="r"&gt;do&lt;/span&gt; |col|
      conn.execute &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;alter table &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;table&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; alter column &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;col&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; type &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;to_type&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; 
                                USING (&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;col&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;::&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;to_type&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;);&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="r"&gt;end&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;
}

change_to_type.call &lt;span class="sy"&gt;:integer&lt;/span&gt;

&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Step 8: Load the data dump into the new database&lt;/h2&gt;

&lt;p&gt;Ah, finally.  Let&amp;#8217;s load the data.  Back to a shell in a directory with the dump, run:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;sed "s/\\\'/\'\'/g" typo.dump | sed "s/\\\r/\r/g" | sed "s/\\\n/\n/g" | psql -1 typo_prod&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pass whatever options you need to connect to psql as you normally would.  The first sed converts all of the &amp;#92;&amp;#8217; to two consecutive &amp;#8216;s, which is what psql expects.  The next two calls to sed in the pipeline replace the escaped carriage returns and newlines with actual carriage returns and newlines, which is again what psql expects.&lt;/p&gt;

&lt;p&gt;You may get a couple warnings, but hopefully no errors.  The few warnings I received were inconsequential.&lt;/p&gt;

&lt;h2&gt;Step 9:  Change the boolean columns back to boolean and restore the default columns&lt;/h2&gt;

&lt;p&gt;Back to our rails console.  We now have the data in place and can change the columns back using our closure from earlier:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;change_to_type.call &lt;span class="sy"&gt;:boolean&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then restore the defaults we dropped:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;defaults.each_pair &lt;span class="r"&gt;do&lt;/span&gt; |table, cols|
  cols.each_pair &lt;span class="r"&gt;do&lt;/span&gt; |col, default|
    conn.execute &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;alter table &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;table&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; alter column &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;col&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; SET DEFAULT &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;default&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Step 10: Repair the sequences.&lt;/h2&gt;

&lt;p&gt;Another annoying aspect of postgresql is that inserting a value into a serial column doesn&amp;#8217;t automatically advance the sequence to be ready to serve up an unused value.  There will be a sequence called &amp;#8220;#{table}_id_seq&amp;#8221; for each table with an id column in the database.&lt;/p&gt;

&lt;p&gt;We manually have to advance all of the sequences:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;conn.tables.each &lt;span class="r"&gt;do&lt;/span&gt; |table|
  &lt;span class="r"&gt;if&lt;/span&gt; conn.columns(table).detect{|i|i.name == &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;}
    conn.execute &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;SELECT setval('&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;table&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;_id_seq', (SELECT max(id) FROM &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;table&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;So that should do it.  Restart your mongrel cluster (or whatever you are using to manage your rails server processes) and you should now be using your blog with a postgresql backend!  &lt;/p&gt;

&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-5048333526809695";
/* 468x60, created 1/4/09 */
google_ad_slot = "3496869414";
google_ad_width = 468;
google_ad_height = 60;
//--&gt;
&lt;/script&gt;

&lt;script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;</description>
      <pubDate>Sun, 04 Jan 2009 23:44:00 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:d0c8a153-3284-4645-b644-7acb4bb92c94</guid>
      <author>azimux@gmail.com (miles)</author>
      <comments>http://nopugs.com/2009/01/04/how-to-migrate-typo-from-mysql-to-postgresql#comments</comments>
      <category>Ruby</category>
      <category>Ruby on Rails</category>
      <category>typo</category>
      <trackback:ping>http://nopugs.com/trackbacks?article_id=18</trackback:ping>
      <link>http://nopugs.com/2009/01/04/how-to-migrate-typo-from-mysql-to-postgresql</link>
    </item>
    <item>
      <title>using permalinks to access articles without specifying the date in typo</title>
      <description>&lt;p&gt;I recently switched from mephisto to typo, mostly due to lack of activity and features in the mephisto project.&lt;/p&gt;

&lt;p&gt;With mephisto, I had to make a modification to allow me to use permalinks without the date to access articles.  For example, so I could say &lt;a href="http://nopugs.com/permalinks-without-dates"&gt;http://nopugs.com/permalinks-without-dates&lt;/a&gt; instead of &lt;a href="http://nopugs.com/2008/09/11/permalinks-without-dates"&gt;http://nopugs.com/2008/09/11/permalinks-without-dates&lt;/a&gt;  I&amp;#8217;m not sure why this isn&amp;#8217;t already a feature of such blogging systems.  I&amp;#8217;m somewhat new to blogging so perhaps there&amp;#8217;s a good reason.  Maybe there are sometimes different articles with the same permalink (I don&amp;#8217;t know why somebody would do this.)&lt;/p&gt;

&lt;p&gt;Regardless, here&amp;#8217;s how I modified typo to allow me to do this.&lt;/p&gt;

&lt;p&gt;In app/controllers/redirect_controller.rb change the redirect method from this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt; &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;redirect&lt;/span&gt;
    &lt;span class="r"&gt;if&lt;/span&gt; (params[&lt;span class="sy"&gt;:from&lt;/span&gt;].first == &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;articles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)
      path = request.path.sub(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;/articles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)
      url_root = request.relative_url_root
      path = url_root + path &lt;span class="r"&gt;unless&lt;/span&gt; url_root.nil?
      redirect_to path, &lt;span class="sy"&gt;:status&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;301&lt;/span&gt;
      &lt;span class="r"&gt;return&lt;/span&gt;
    &lt;span class="r"&gt;end&lt;/span&gt;

    r = &lt;span class="co"&gt;Redirect&lt;/span&gt;.find_by_from_path(params[&lt;span class="sy"&gt;:from&lt;/span&gt;].join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;))

    &lt;span class="r"&gt;if&lt;/span&gt;(r)
      path = r.to_path
      url_root = request.relative_url_root
      path = url_root + path &lt;span class="r"&gt;unless&lt;/span&gt; url_root.nil? &lt;span class="r"&gt;or&lt;/span&gt; path[&lt;span class="i"&gt;0&lt;/span&gt;,url_root.length] == url_root
      redirect_to path, &lt;span class="sy"&gt;:status&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;301&lt;/span&gt;
    &lt;span class="r"&gt;else&lt;/span&gt;
      render &lt;span class="sy"&gt;:text&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Page not found&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:status&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;404&lt;/span&gt;
    &lt;span class="r"&gt;end&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;to this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;redirect&lt;/span&gt;
    &lt;span class="r"&gt;if&lt;/span&gt; (params[&lt;span class="sy"&gt;:from&lt;/span&gt;].first == &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;articles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)
      path = request.path.sub(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;/articles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)
      url_root = request.relative_url_root
      path = url_root + path &lt;span class="r"&gt;unless&lt;/span&gt; url_root.nil?
      redirect_to path, &lt;span class="sy"&gt;:status&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;301&lt;/span&gt;
      &lt;span class="r"&gt;return&lt;/span&gt;
    &lt;span class="r"&gt;end&lt;/span&gt;

    article = &lt;span class="co"&gt;Article&lt;/span&gt;.find_by_permalink(params[&lt;span class="sy"&gt;:from&lt;/span&gt;].first)

    &lt;span class="r"&gt;if&lt;/span&gt; article
      redirect_to article_path(article)
      &lt;span class="r"&gt;return&lt;/span&gt;
    &lt;span class="r"&gt;end&lt;/span&gt;

    r = &lt;span class="co"&gt;Redirect&lt;/span&gt;.find_by_from_path(params[&lt;span class="sy"&gt;:from&lt;/span&gt;].join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;))

    &lt;span class="r"&gt;if&lt;/span&gt;(r)
      path = r.to_path
      url_root = request.relative_url_root
      path = url_root + path &lt;span class="r"&gt;unless&lt;/span&gt; url_root.nil? &lt;span class="r"&gt;or&lt;/span&gt; path[&lt;span class="i"&gt;0&lt;/span&gt;,url_root.length] == url_root
      redirect_to path, &lt;span class="sy"&gt;:status&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;301&lt;/span&gt;
    &lt;span class="r"&gt;else&lt;/span&gt;
      render &lt;span class="sy"&gt;:text&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Page not found&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:status&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;404&lt;/span&gt;
    &lt;span class="r"&gt;end&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then in app/models/article.rb change find_by_permalink from this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.find_by_permalink(year, month=&lt;span class="pc"&gt;nil&lt;/span&gt;, day=&lt;span class="pc"&gt;nil&lt;/span&gt;, title=&lt;span class="pc"&gt;nil&lt;/span&gt;)
    &lt;span class="r"&gt;unless&lt;/span&gt; month
      &lt;span class="r"&gt;case&lt;/span&gt; year
      &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="co"&gt;Hash&lt;/span&gt;
        year, month, day, title = date_from(year)
      &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="co"&gt;Array&lt;/span&gt;
        year, month, day, title = year
      &lt;span class="r"&gt;end&lt;/span&gt;
    &lt;span class="r"&gt;end&lt;/span&gt;
    date_range = &lt;span class="pc"&gt;self&lt;/span&gt;.time_delta(year, month, day)
    find_published(&lt;span class="sy"&gt;:first&lt;/span&gt;,
                   &lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt; { &lt;span class="sy"&gt;:permalink&lt;/span&gt; =&amp;gt; title,
                                    &lt;span class="sy"&gt;:published_at&lt;/span&gt; =&amp;gt; date_range }) \
      &lt;span class="r"&gt;or&lt;/span&gt; raise &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;RecordNotFound&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;to this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;pre&gt;&lt;span class="CodeRay"&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.find_by_permalink(year, month=&lt;span class="pc"&gt;nil&lt;/span&gt;, day=&lt;span class="pc"&gt;nil&lt;/span&gt;, title=&lt;span class="pc"&gt;nil&lt;/span&gt;)
    &lt;span class="r"&gt;unless&lt;/span&gt; month
      &lt;span class="r"&gt;case&lt;/span&gt; year
      &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="co"&gt;Hash&lt;/span&gt;
        year, month, day, title = date_from(year)
      &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="co"&gt;Array&lt;/span&gt;
        year, month, day, title = year
      &lt;span class="r"&gt;end&lt;/span&gt;
    &lt;span class="r"&gt;end&lt;/span&gt;

    &lt;span class="r"&gt;if&lt;/span&gt; year &amp;amp;&amp;amp; !month &amp;amp;&amp;amp; !day &amp;amp;&amp;amp; !title
      year, title = title, year
    &lt;span class="r"&gt;end&lt;/span&gt;

    published = &lt;span class="pc"&gt;nil&lt;/span&gt;

    &lt;span class="r"&gt;if&lt;/span&gt; year
      date_range = &lt;span class="pc"&gt;self&lt;/span&gt;.time_delta(year, month, day)
      published = find_published(&lt;span class="sy"&gt;:first&lt;/span&gt;,
        &lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt; { &lt;span class="sy"&gt;:permalink&lt;/span&gt; =&amp;gt; title,
          &lt;span class="sy"&gt;:published_at&lt;/span&gt; =&amp;gt; date_range }) 
    &lt;span class="r"&gt;end&lt;/span&gt;

    &lt;span class="r"&gt;unless&lt;/span&gt; published
      published = find_published(&lt;span class="sy"&gt;:first&lt;/span&gt;, &lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:permalink&lt;/span&gt; =&amp;gt; title})
    &lt;span class="r"&gt;end&lt;/span&gt;

    raise &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;RecordNotFound&lt;/span&gt; &lt;span class="r"&gt;unless&lt;/span&gt; published
    published
  &lt;span class="r"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you should be able to leave the year/month/day off of your article URLs when sharing them with friends and such.  &lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-5048333526809695";
/* 468x60, created 9/12/08 */
google_ad_slot = "5994986434";
google_ad_width = 468;
google_ad_height = 60;
//--&gt;
&lt;/script&gt;

&lt;script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;</description>
      <pubDate>Thu, 11 Sep 2008 18:59:00 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:7ef07d2e-a28c-45b5-b046-e0d3573ae710</guid>
      <author>azimux@gmail.com (miles)</author>
      <comments>http://nopugs.com/2008/09/11/permalinks-without-dates#comments</comments>
      <category>typo</category>
      <link>http://nopugs.com/2008/09/11/permalinks-without-dates</link>
    </item>
  </channel>
</rss>
