Mon, 12 Jul 2010 21:47:00 GMT

Moving onrails.org to Typo 5.4.x, Rails 2.3.8 on Heroku

So why Heroku and why not leave my server on slicehost? I don’t have any issue with the slice but I want to upgrade the version of Typo just to stay uptodate and while at it wanted to explore a little. So of course I found an article on Getting Typo 5.4 running on Heroku So I gave it a try.

The interesting part is that onrails.org has been around since forever and I also had to migrate the database. Onrails.org was running on a version of Typo 4.

setting the blog up locally

First I’ve downloaded my older typo MySQL database and restored it locally. I’ve copied Typo from here or you can clone the Typo git repository.

$ git clone http://github.com/fdv/typo.git 

I changed the database.yml to point to my database. Did a rake gems:install, followed by a rake db:migrate and had now a local install of my blog.

creating a heroku app

The goal was to try to deploy the blog to heroku. So here you can create an empty

$ heroku create onrails
git@heroku.com:onrails.git
$ git init
$ git add .
$ git commit -m "Adding onrails.org using typo 5.4.4"

I then followed joels’ article to "heroku"fy Typo. So I basically created a few empty folders and replaced FileUtils by FileUtils::NoWrite. Note sure if that last change would cripple Typo but things seems to work fine.

Then I created a .gems files that is used by heroku instead of Bundler.

.gems
	rails = 2.3.8
	htmlentities  
	json 
	calendar_date_select 
	bluecloth  ~> 2.0.5
	coderay  ~> 0.8
	mislav-will_paginate  ~> 2.3.11 --source gems.github.com
	RedCloth  ~> 4.2.2
	panztel-actionwebservice  = 2.3.5
	addressable  ~> 2.1.0
	mini_magick  ~> 1.2.5

Finally I deployed the app with an empty database:

$ git remote add heroku git@heroku.com:onrails.git
$ git push heroku master
$ heroku rake db:migrate   # with empty db

That’s it that gets you an install of Typo on Heroku. Note, keep reading for a few gotcha’s I found in regards to Rails 2.3.8.

Rails 2.3.8 on heroku

At the time of this writing Rails 2.3.8 wasn’t the default on Heroku, but fortunately they support a different stack with Rails 2.3.8. To switch I just had to do the following:

$ heroku stack:migrate bamboo-ree-1.8.7

Migrating the local MySQL database to Heroku’s Postgres database.

It’s a rather straight forward process…just do

$ heroku db:push

This converted the database and replaced the remote database with my local data on Heroku. It converts my MySQL database to a Postgress database without having to specify anything…But there was on gotcha. The Sidebar table id column turned out as “text” instead of an “integer”. And this caused some of the admin functionality to fail, i.e. reconfiguring the sidebar. The other tables where converted correctly and I saw that the local Sidebar id column was slightly different than the other id columns. For some reasons the sidebar table id column type was a "signed int’ and that translated to a text field when doing the db:push. So I just unchecked the signed flag and the db:push went smoothly.

legacy permalinks

Somehow the articles and category links are all prefixed with “/articles” on onrails.org. I don’t know if that was due to some default setting in Typo 4 or due to the fact that I started with a way earlier version of Typo. In any case I preferred to use the new links formats that just drops the “/articles”, but that would also mean breaking a lot of incoming links. So I just configured Typo to support the legacy permalinks via these added routes

  # Legacy permalink format support
  map.connect '/articles/:year/:month', :controller => 'articles', :action => 'index', :year => /\d{4}/, :month => /\d{1,2}/
  map.connect '/articles/:year/:month/page/:page', :controller => 'articles', :action => 'index', :year => /\d{4}/, :month => /\d{1,2}/
  map.connect '/articles/:year', :controller => 'articles', :action => 'index', :year => /\d{4}/
  map.connect '/articles/:year/page/:page', :controller => 'articles', :action => 'index', :year => /\d{4}/   

 # Legacy permalink format support
  map.resources :categories, :except => [:show, :update, :destroy, :edit], :path_prefix => '/articles'
  map.resources :categories, :as => 'category', :only => [:show, :edit, :update, :destroy], :path_prefix => '/articles'

  map.connect '/articles/category/:id/page/:page', :controller => 'categories', :action => 'show'

Now the blog supports both new and old formats. Note that the url for the articles can be modified in the settings, but I didn’t find settings for the category permalinks and supporting both old and new format gives me a smooth transition forward.

Rails and Issue with Typo workaround?

I was getting the following error when doing certain actions on the blog:

ActionView::TemplateError (undefined method `interpolate_without_deprecated_syntax' for #<I18n::Backend::Simple:0x2b8d1ef90700>) on line #5 of themes/scribbish/views/articles/_comment.html.erb:

So I assumed this was some compatibility between Typo and Rails and Typo had a workaround defined in the environment.rb file file. As I use Rails 2.3.8 I disabled that workaround and everything seems to work again:

So I just removed the followed lines from the enviroment.rb file:

environment.rb
class I18n::Backend::Simple
  def interpolate(locale, string, values = {})
    interpolate_without_deprecated_syntax(locale, string, values)
  end
end

custom domain

I’m sure there are a few more details I missed and hope my readers will point them out, but let’s jump and turn the switch on.

So you need to switch on custom domains on heroku as follows:

$heroku addons:add custom_domains
$ heroku domains:add www.onrails.org
Added www.onrails.orgas a custom domain name to onrails.heroku.com 
$ heroku domains:add onrails.org
Added onrails.orgas a custom domain name to onrails.heroku.com

Then I went on to pointed my dns to Heroku.

The move is complete but the dns change to point to heroku still may take some time. So if you see the Scribbish theme you are still on the old server and if you see the Elegant Grunge theme you are right here on Heroku.

Enjoy,
Daniel

UPDATE 1: the dns updated www.onrails.org and onrails.org at different time. And all the images of the new sites where using urls of the old site and everything looked pristine. No more…So a hidden issue is that Typo let’s you upload files like images which are stored in the resources table and also copied to to the public/files folder. This is a convenient way to serve files and images for your blog entries. Well, that won’t work very well while on heroku especially since we really made the file system read only. I need to read more on how to enable page caching on Heroku and see if it is compatible with Typo. If not… I will need to revert back to my previous host. For now I’ll just add the files via git…and that’s not a solution.


Fri, 11 Jun 2010 05:30:00 GMT

RailsConf 2010 - Thank You!

Wow, RailsConf is over. It ended nicely with @garyvee giving a powerful and entertaining keynote covering many subjects but mostly his standard spiel on connecting with your customers or audience. I read his book, crush it, a while back and enjoyed it. Note since, I haven’t been the most active on my blog or website??but I’m working on changing this.

Now of course RailsConf was way more that this keynote. I must admit I really enjoyed Baltimore and having the convention center, the hotel and the port at a five minutes walking distance. It’s a great area, I understand that not the whole city is like that, but that doesn’t remove anything from the fact that I really appreciate the place right now.

The best thing at this conference is the energy that transpires and I really feel energized and want to start some new Rails venture. It’s fun to see so many enthusiasts trying to learn, share, and push the community forward.

I must admit I usually enjoy smaller conferences, like the MoutainWest RubyConf or the forthcoming Moutain.rb, better as the tracks are more specialized and geekier. RailsConf tries to have several tracks for everybody but very few are very technical. Maybe the organizers should try to have an advanced track next time. That way the conference would stay appealing for the many people that have been doing Rails/Ruby for years and still be welcoming for beginners.

As usual there are always some talks that just suck. On the tutorial day I attended in the afternoon Rails 3 Deep Dive and it wasn’t about Rails 3 nor a deep dive. Another talk that didn’t turn out the way it should have been was Scaling Rails on AppEngine with JRuby and Duby where the speakers where knowledgeable but where note prepared enough and where counting on the wifi to work??The wifi never works at conference. This said the wifi was usually working pretty well at RailsConf this time.

I don’t wanna focus too much on the talks that didn’t work out as most of the talks where great and also not all my talks in the past always worked out they way they could have ;-)

One of the tutorial I really liked was Acceptance Testing With Cucumber. David Chelimsky rocked and just knows his stuff and Aslak hanged in there pretty well. They had an application prepared with multiple branches that let the audience follow right along. That was great. They didn’t have time to access a few of the advanced Cucumber subjects??next time make that a full day tutorial.

The first talk I attended on tuesday was Building an API with Rails which was a panel discussion with guys from Twitter, 37Signals, Github, the NYT and others. I really enjoyed that there was several distinct views on several aspects like on APIs like versioning, security, performance which relates exactly with some customer work I’m currently doing.

Then I went to the Metrics Magic by Aaron Bedra from Relevance which cover tools like RCov,Flog, Flay, Roodi, Reek and how to integrate them with your continuous integration build. For example why don’t you make your build fail when it reaches a certain threshold of uncovered code (let’s say 20%)??I like that idea. We do generate these stats in our ci builds but don’t fail the builds??yet.

Another great panel on tuesday was The State of Rails e-Commerce. I’m interested in ecommerce since the first of Rails project I worked on end of 2005.

Then I went to see Ilya Grigorik talk on “No callbacks, no threads: async & cooperative web servers with Ruby 1.9”??I just wish all the task where that awesome??Ilya tries to push the current stack of Ruby technologies to the next step to try to get the same benefits than what node.js provides??and he showed us how. Wow.

I’m not gonna list all the talks I attended here, but will provide a few more comments. There where two business oriented talks I enjoyed, the Million Dollar Mongo by Obie Fernandez and Durran Jordan from Hashrocket and the Agile the Pivotal Way talk by Ian MCFarland. Ian’s presented how his teams operates and I now see why Pivotal is on such a growth path. There are many cool aspects they are enforcing, one key I believe is to have really agile team members than can switch in an out of each team while still providing continuity to the customer by having one anchor member. Another essential aspect is the culture and how they propagate it buy doing peer programing to the extreme. Obie’s talk was an interesting retrospective on a very large project (10’0000 hours) they undertook. What surprised me is that he was pretty negative on his client and also went after some members of the Rails community??Well, maybe Hashrocket should stick to smaller projects ;-)

What else was cool? Rich Kilmer gave a nice talk about Authentication in a RESTful World. Again, that’s totally relevant to a customer project of mine. One of the best talks out there was Rocket Fueled Cucumbers by Joseph Wilk, but I saw only the last quarter as I selected another talk that I decided to leave??too late.

Matthew Deiters also gave a presentation I really enjoyed about “Recommendations in Rails”??something I may have to build in one of my apps very soon. I’m less exited about the fact that he recommends a java tool (Neo4j) to manage your graph of relations??but I trust him that it’s the best of the solutions out there for now.

Besides the talks Bluebox threw a party at a local bar, besides the fact that Fernand managed to get us lost on they way and I wasn’t sure we would survive the neighborhood we ended up in??the party was great and we met one of the Bluebox software developers and her mam and had a great time. At least I think so based on the trouble I had to wake up the next day.

I had fun with the keynotes. Derek Sivers gave a talk which I enjoyed even though it was not related to Rails but it was very entertaining. I really liked Yehuda Katz talk and he his certainly the driving factor behind Rails 3 but he gave a lot of credits to specific members of the community which took on many issues that most thought where impossible to address or change and fixed them.

The Ruby Heroe Awards Ceremony is always fun to watch, and Gregg puts lots of effort into making them happen. Next time just let the winners make a thank speech??that would stress them a little.

Overall there wasn’t enough coverage of Rails 3, I guess that’s gonna for next year when everyone migrated all there projects to it.

So reflecting on these 4 past days??it was a great conference. A big thanks to the organizers and all the presenters

Now time to kick off a new Rails 3 project.

Enjoy!
Daniel


Wed, 28 Apr 2010 00:42:00 GMT

Making CRUD less "Cruddy", one step at a time

One of the great “new” features of Rails (as of 2.3) is accepts_nested_attributes_for, allowing you to build cross-model CRUD forms without “cruddying” your controller. There are some great examples out there about how to do this, but I’d like to walk thorough a particular use case — managing the “join” records in a has_many :through relationship.

Consider the following database schema:

class Villain < ActiveRecord::Base
  has_many :gifts
  has_many :super_powers, :through => :gifts
end

class Gift < ActiveRecord::Base
  belongs_to :villain
  belongs_to :super_power

  validates_uniqueness_of :super_power, :scope => :villain_id
end

class SuperPower < ActiveRecord::Base
  has_many :gifts
  has_many :villains, :through => :gifts
end

In our dataset, there are a relatively small number of super powers which we wish to present as a list of checkboxes on the villain management form. Checking/unchecking the boxes will manage the gift records for that villain, effectively managing the list of super powers available to the baddy.

To get started, we need to add accepts_nested_attributes_for :gifts to the Villain class — piece of cake. To complete the implementation, we need to change the params hash that our form generates. Let’s review the cases that we need to support and the associated params hash format needed to implement the correct functionality.

The first case is a super power record that is not currently associated with the villain. Here, the UI should display an unchecked checkbox. If we check it and submit the form, a gift record should be created linking the villain with the super power, making this bad guy that much badder. Here is an example of the params hash we should be sending to accomplish this:

  {
    'villain' => {
      'name' => 'Lex Luthor',
      ...
      'gifts_attributes' => {
        1 => { 'super_power_id' => 5 },
        2 => { 'super_power_id' => 7 },
        ...
      }
    }
  }

The alternate case is a super power this villain already possesses. In this instance, the UI should display a checked checkbox, and if we uncheck it, the existing gift record should be deleted, diminishing the villain’s capacity for evil. And our params hash needs to look like:

  {
    'villain' => {
      'name' => 'Two-Face',
      ...
      'gifts_attributes' => {
        1 => { 'id' => 101, '_delete' => true },
        ...
      }
    }
  }

Note that the keys for the gifts_attributes hash are arbitrary; we can use any scheme to generate unique keys for the hash.

So how can we craft a form that sends the params hash that Rails wants to see? Here’s my implementation:

  <%- SuperPower.all.each_with_index do |super_power, index| -%>
    <label>
      <%- if gift = @villain.gifts.find_by_super_power_id(super_power.id) -%>
        <%= hidden_field_tag "villain[gifts_attributes][#{ index }][id]", gift.id %>
        <%= check_box_tag "villain[gifts_attributes][#{ index }][_delete]", false, true %>
        <%= hidden_field_tag "villain[gifts_attributes][#{ index }][_delete]", true %>
      <%- else -%>
        <%= check_box_tag "villain[gifts_attributes][#{ index }][super_power_id]", super_power.id %>
      <%- end -%>

      <%= super_power.name %>
    </label><br />
  <%- end -%>

If the gift is detected, the villain has the super power, and we handle our second case from above, using the checkbox / hidden field hack Rails employs in the check_box helper method to make sure a value is sent whether or not the checkbox is checked. The else block handles the other case, setting up our params hash to create the gift if the checkbox is checked.

This works, but we probably don’t want to copy and paste that code everywhere we use this pattern. How can we reuse this in a DRY fashion? Here’s a helper method that encapsulates the logic:

  def has_join_relationship(model, join_collection_name, related_item, collection_index, options={})
    returning "" do |output|
      relationship_name = options[:relationship_name] || related_item.class.table_name.singularize + "_id"
      tag_prefix = "#{ model.class.class_name.underscore }[#{ join_collection_name }_attributes][#{ collection_index }]"

      if join_item = model.send(join_collection_name).find(:first, :conditions => { relationship_name => related_item.id })
        output << hidden_field_tag("#{ tag_prefix }[id]", related_item.id)
        output << check_box_tag("#{ tag_prefix }[_delete]", false, true)
        output << hidden_field_tag("#{ tag_prefix }[_delete]", true)
      else
        output << check_box_tag("#{ tag_prefix }[#{ relationship_name }]", related_item.id, false)
      end
    end
  end

Drop that in a helper, and then your form code becomes:

  <%- SuperPower.all.each_with_index do |super_power, index| -%>
    <label>
      <%= has_join_relationship(@villain, :gifts, super_power, index) %>
      <%= super_power.name %>
    </label><br />
  <%- end -%>

Much nicer … although I’m not sold on the name has_join_relationship. Any suggestions?


Wed, 07 Apr 2010 04:13:00 GMT

Cucumber, meet Routes

I’ve been loving Rails BDD with Cucumber for the past year or so — it helps me focus on the next required step to build a feature in my application, and better focus equals better development velocity. However, one thing I found tedious in starting with Cucumber was defining route matchers in paths.rb.

The stock path_to method is implemented as a case statement, allowing you to add a case for each path you want to recognize. This works, but leaves you feeling a bit un-DRY since you’re basically duplicating information in your routes.rb file.

Here’s a quick hack to paths.rb that lets you leverage your existing routes:

change

    else
      raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
        "Now, go and add a mapping in #{__FILE__}"
    end

to

    else
      begin
        page_name =~ /the (.*) page/
        path_components = $1.split(/\s+/)
        self.send(path_components.push('path').join('_').to_sym)
      rescue Object => e
        raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
          "Now, go and add a mapping in #{__FILE__}"
      end
    end

In your Cucumber steps, you can now use any named route that does not require a parameter. For example, users_path would become “the users page”, and new_product_path would become “the new product page”. As you add new resources, at least the index and new options should work out of the box — no further edits to paths.rb required!

UPDATE:

w00t!

This is now baked into cucumber-rails!


Thu, 11 Mar 2010 23:53:46 GMT

MWRC 2010 - Day 1 Live Video

Moutains Pano + fingers

The conference is about to start in 30 minutes, the room starts to buzz. The confreaks guys have their camera and video recording equipment all setup. So you will be able to catch up the conference online soon. Somehow I really like single track conferences and the sessions seem really great and will be fast passed, 30 to 45 minutes. Check out the schedule. So I will sit back and enjoy the show.

Follow it live on Justin TV!!

Watch live video from Mountain West Ruby Conference on Justin.tv

Salt Lake City is definitively a beautiful city, surrounded by it’s mountains…

Library

Library


Fri, 19 Feb 2010 03:14:00 GMT

Rails 3: Rack Middleware

I’m watching the Rails Online Conference, February 2010 Exploring Rails 3 and really like how they setup the rack middleware.

…From the slides.

Rack Middleware

http://github.com/rack/rack/tree/master/lib/rack

Content Modifying

Rack::Chunked
Rack::ContentLength
Rack::ConditionalGet
Rack::ContentType
Rack::Deflater
Rack::ETag
Rack::Head
Rack::MethodOverride
Rack::Runtime
Rack::Sendfile
Rack::ShowStatus

Behavioral

Rack::CommonLogger
Rack::Lint
Rack::Lock
Rack::Reloader

Routing

Rack::Cascade
Rack::Recursive
Rack::Static
Rack::URLMap

Rack::Contrib

http://github.com/rack/rack-contrib

Rack::AcceptFormat
Rack::Access
Rack::Backstage
Rack::Callbacks
Rack::Config
Rack::Cookies
Rack::CSSHTTPRequest
Rack::Deflect
Rack::Evil
Rack::HostMeta
Rack::JSONP
Rack::LighttpdScriptNameFix
Rack::Locale
Rack::MailExceptions
Rack::NestedParams
Rack::NotFound
Rack::ProcTitle
Rack::Profiler
Rack::ResponseCache
Rack::ResponseHeaders
Rack::RelativeRedirect
Rack::Signals
Rack::SimpleEndpoint
Rack::TimeZone

Coderack.org

Check also out http://coderack.org …99 pieces of Rack Middleware

RailsGuide: Rails On Rack

http://guides.rubyonrails.org/rails_on_rack.html


Thu, 18 Feb 2010 11:15:03 GMT

Time.onrails.org is closing!

I just send an email to thousands of users to notify them that time.onrails.org is closing down. I don’t think many of these users are active but just in case I wanted everyone to be able to get their data out of the system if so they wished.

I will turn down the service on March 17th at 9pm.

Now why in the hell would I close this service. In brief I created it for myself on the plane to RubyConf 2005, thought it was cool and opened it to the public in April 2006. I haven’t updated the code much since many years and just don’t have the time to add new features, and trust me Rails code from 2005 looks slightly different than nowadays Rails code.

For posterity here is the “official” announcement blog entry of the creation of the service:

April 13, 2006 – LAUNCH time.onrails.org, time tracking made simple!

And here are few more articles related to time.onrails.org.

Here is part of the email I send to the users:


Time.onrails.org is closing down March 17th 2010 at 9pm Mountain time.

You can export your time entry for each project by clicking on the export buttons at the bottom of each project page or you can export your full account by just login and then go to this url:

? ? http://time.onrails.org/export/xml/user

This will export each of the projects will all sections including the notes.

Please start transitioning to a new service now.

As a replacement service I would suggest harvest (http://www.getharvest.com/) which offers a free plan which allows for 2 projects, 4 clients, unlimited invoicing for 1 user absolutely FREE.

Thank you to all the users over the years I hope you enjoyed this free service. Time.onrails.org enjoyed thousands of users and I received many nice complimenting emails for the service over the years. The main reason that I close this service is that I am starting to use harvestapp for my own time tracking. I wrote time.onrails.org back in 2005 just for fun and thought it could be useful to others. It fulfilled my needs of keeping track of time for the various customer projects I worked on over the last few years.

Since we moved to slicehost it was very stable and I just have good things to say about slicehost, they are just great. Recently one of the slice time.onrails.org was running on had issues and got moved twice over two days. Again slicehost was on top of that situation and I just sat back and they did all the work. But this also reminded me that I cannot just keep the service running without giving it the time and effort it deserves and just now I don’t have that time as I am working on other projects, such as http://appsden.com.

So I went on the search for a replacement service and ???looked at many out there. And Harvest just added the timestamp feature, which is exactly how I track time, their app is more fleshed out than time.onrails.org, so I decided to move over to use their services.

The great news is while I tweeted about my move to Harvest, Doug, which I knew from his time in Denver mentioned that he now works for Harvest. So he put me in contact with the cofounder and I asked him if they could get some deal for my current users, and they where very responsive and create a special promo code. Thanks for that and I hope you try and enjoy their services. Just for disclaimer I didn’t ask for any monetization or anything for referring you to Harvest, the idea was just to have an alternate offering in case you needed one. But they offered me a free Solo plan, so hey, at least I got that out of this whole ordeal.

Please don’t hesitate to contact me for any question at daniel@onrails.org.

Thank you again for having tried out or being a user of time.onrails.org over all these years.

Kind regards,
Daniel Wanja


Thu, 29 Oct 2009 10:02:27 GMT

Amazon RDS: Amazon Relational Database Service or MySQL in the Cloud for Ruby On Rails.

For watchthatsite.com (not public yet) I have an instance on EC2 with Rails and MySQL but was looking for a more solid hosting solution for MySQL. And how fortunate, Amazon came out with the solution I need this week. Basically with two command line instructions you can start a new server with mysql configured, tuned, and secured. In this blog entry I will go through the steps that perform to move my sql database to Amazon RDS.

You can find more information on Amazon Relational Database Service (API Version 2009-10-16) here.

Prerequisite: you need to signup for an account on aws.amazon.com, it can be used for EC2, S3, SimpleDb and all the other services AWS provides.

1) Install the Command Line Toolkit

First thing, go download the command line toolkit and read the README.TXT on how to install it. In short you unzip the files, I did put mine at /Developer/aws/RDSCli-1.0.001. Then you create a credential file which contains your AWS access key id and secret key. Then I configured my ~/.bash_profile as follows:

export AWS_RDS_HOME=/Developer/aws/RDSCli-1.0.001
export AWS_CREDENTIAL_FILE=$AWS_RDS_HOME/credential-file-path.conf
export JAVA_HOME=/Library/Java/Home
export PATH=$AWS_RDS_HOME/bin:$PATH

to see that the command line toolkit is setup correctly type $rds —help

You will need the command line tool to execute several commands described here after.

2) Create an Instance

Let’s create a MySQL Server instance. RDS offers the following 5 server instance classes:

  • db.m1.small (1.7 GB of RAM, $0.11 per hour)
  • db.m1.large (7.5 GB of RAM, $0.44 per hour)
  • db.m1.xlarge (15 GB of RAM, $0.88 per hour)
  • db.m2.2xlarge (34 GB of RAM, $1.55 per hour)
  • db.m2.4xlarge (68 GB of RAM, $3.10 per hour)

I will choose a small instance which I will call dbserver1 with a database name db1 and allocate 5g of database space. I also set the master username as admin and password as secret.

$ rds-create-db-instance --db-instance-identifier db1 --allocated-storage 5 --db-instance-class db.m1.small --engine MySQL5.1 --master-username admin --master-user-password secret --db-name db1 --headers

The output is the following:

DBINSTANCE  DBInstanceId  Class        Engine    Storage  Master Username  Status    Backup Retention
DBINSTANCE  db1           db.m1.small  mysql5.1  5        admin            creating  1               
      SECGROUP  Name     Status
      SECGROUP  default  active
      PARAMGRP  Group Name        Apply Status
      PARAMGRP  default.mysql5.1  in-sync

Now you have a server running and you are being billed $0.11 per hour, that’s like $80 a month without bandwidth but with backup…and it took only 2 minutes to get going. Can’t beat that.

To see all the instances you have you can issue the

rds-describe-db-instances --headers

3) Grant Network Access

So I will grant access from my notebook, assuming the ip address is 24.19.0.48 (you can also specify ranges i.e. 24.19.0.0/50). (Note that access was revoked by AWS, not sure why??)

rds-authorize-db-security-group-ingress default --cidr-ip 24.19.0.48 --headers

I also have an ec2 instance which I want to grant access to

rds-authorize-db-security-group-ingress default --ec2-security-group-name watchthatsite --ec2-security-group-owner-id 526541544691

Note the ec2-security-group-owner-id is your Amazon AWS account number, you can find it for example on you account activity page. To see your security configuration issue the following command: rds-describe-db-security-groups default —headers

4) Using the Database

To use your database you first need to find out the endpoint address of your new server. So describe you instances:

rds-describe-db-instances --headers command
DBINSTANCE  DBInstanceId  Created                   Class        Engine    Storage  Master Username  Status     Endpoint Address                              Port  AZ          Backup Retention
DBINSTANCE  db1           2009-10-28T22:53:31.666Z  db.m1.small  mysql5.1  5        admin            available  db1.cyhik6zpub5c.us-east-1.rds.amazonaws.com  3306  us-east-1b  1               
      SECGROUP  Name     Status
      SECGROUP  default  active
      PARAMGRP  Group Name        Apply Status
      PARAMGRP  default.mysql5.1  in-sync

You find out your endpoint address, for me db1.cyhik6zpub5c.us-east-1.rds.amazonaws.com

So now you can connect to your database:

mysql -h db1.cyhik6zpub5c.us-east-1.rds.amazonaws.com -P 3306 -u admin -p db1

Let’s configure my Rails application to point to that database and run a migration:

So I change my config/database.yml to point to the above database

development:
    adapter: mysql
    host: db1.cyhik6zpub5c.us-east-1.rds.amazonaws.com
    reconnect: false
    database: db1
    username: admin
    password: secret
 rake db:migrate

Wow, seem to work.

Let connect to the mysql console and do a show tables;

+-------------------+
| Tables_in_db1     |
+-------------------+
| schema_migrations | 
| users             | 
| watches           | 
+-------------------+

Yep, all there.

Now I still have to move my old production database to the new one, so let’s dump the data from my old database:

mysqldump watchthatsite_development -u admin > wts.sql

and reload that data in the new database:

mysql -h db1.cyhik6zpub5c.us-east-1.rds.amazonaws.com -P 3306 -u admin -p db1 < wts.sql

Restarting my Rails server??That’s all!

Enjoy,
Daniel.


Fri, 04 Sep 2009 07:31:00 GMT

RMagick (from source) on Snow Leopard

After the release of 10.5, I published an article about building RMagick from source on Leopard. I won’t rehash the why, you can read the original article for that. My clean install necessitated updating the RMagick script, so here’s what worked for me to install from source on Snow Leopard! For the impatient, here’s the download link: rmagick-build.sh

First, we start with installing wget, as it seems to be a bit more clever than curl about dealing with mirrors, etc. Then, we compile and install each prerequisite package. Finally, we install the gem.

All the links in the script worked for me, but, depending on your location, network, conditions, etc, your mileage may vary. Enjoy!

#!/bin/sh

# install wget, which is cleverer than curl
curl -O http://ftp.gnu.org/gnu/wget/wget-1.11.tar.gz
tar zxvf wget-1.11.tar.gz 
cd wget-1.11
./configure --prefix=/usr/local
make
sudo make install
cd /usr/local/src

# prerequisite packages
wget http://nongnu.askapache.com/freetype/freetype-2.3.9.tar.gz
tar zxvf freetype-2.3.9.tar.gz
cd freetype-2.3.9
./configure --prefix=/usr/local
make
sudo make install
cd /usr/local/src

wget http://superb-west.dl.sourceforge.net/sourceforge/libpng/libpng-1.2.39.tar.gz
tar zxvf libpng-1.2.39.tar.gz
cd libpng-1.2.39
./configure --prefix=/usr/local
make
sudo make install
cd /usr/local/src

wget ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz
tar xzvf jpegsrc.v6b.tar.gz
cd jpeg-6b
ln -s `which glibtool` ./libtool
export MACOSX_DEPLOYMENT_TARGET=10.6
./configure --enable-shared --prefix=/usr/local
make
sudo make install
cd /usr/local/src

wget ftp://ftp.remotesensing.org/libtiff/tiff-3.9.1.tar.gz
tar xzvf tiff-3.9.1.tar.gz
cd tiff-3.9.1
./configure --prefix=/usr/local
make
sudo make install
cd /usr/local/src

wget http://superb-west.dl.sourceforge.net/sourceforge/wvware/libwmf-0.2.8.4.tar.gz
tar xzvf libwmf-0.2.8.4.tar.gz
cd libwmf-0.2.8.4
make clean
./configure
make
sudo make install
cd /usr/local/src

wget http://www.littlecms.com/lcms-1.17.tar.gz
tar xzvf lcms-1.17.tar.gz
cd lcms-1.17
make clean
./configure
make
sudo make install
cd /usr/local/src

wget ftp://mirror.cs.wisc.edu/pub/mirrors/ghost/GPL/gs870/ghostscript-8.70.tar.gz
tar zxvf ghostscript-8.70.tar.gz
cd ghostscript-8.70
./configure  --prefix=/usr/local
make
sudo make install
cd /usr/local/src

wget ftp://mirror.cs.wisc.edu/pub/mirrors/ghost/GPL/gs860/ghostscript-fonts-std-8.11.tar.gz
tar zxvf ghostscript-fonts-std-8.11.tar.gz
sudo mv fonts /usr/local/share/ghostscript

# Image Magick
wget ftp://ftp.fifi.org/pub/ImageMagick/ImageMagick.tar.gz
tar xzvf ImageMagick.tar.gz
cd `ls | grep ImageMagick-`
export CPPFLAGS=-I/usr/local/include
export LDFLAGS=-L/usr/local/lib
./configure --prefix=/usr/local --disable-static --with-modules --without-perl --without-magick-plus-plus --with-quantum-depth=8 --with-gs-font-dir=/usr/local/share/ghostscript/fonts --disable-openmp
make
sudo make install
cd /usr/local/src

# RMagick
sudo gem install rmagick

UPDATE There is a bug with libgomp that breaks the convert utility (See comments below). the --disable-openmp configure option has been added to the script to fix this.

UPDATE 2 A new patchlevel of ImageMagick has been released that supersedes the original one referenced in this script, and the original has been removed from the server. Thanks to Sebastian for this update that will grab the latest release.


Wed, 05 Aug 2009 06:51:00 GMT

Introducing Hashdown

If your database is normalized, you will almost always end up with small tables (often referred to as reference data or lookup tables) which provide a set of possible values for a particular attribute. (e.g. Currency, Category, etc.) A common pattern that emerges in many applications is accessing these records by a symbolic name (as opposed to by id) for purposes of clarity when reading the code. In C (and friends), the database ids can be mapped to the positions of an enum datatype. I recently released the hashdown plugin that provides hash-like access for reference data records, and also adds some dropdown option list generation support, since this data is often used to populate select list in forms.

As an example of what hashdown does, suppose we have the following model:

class CardType < ActiveRecord::Base
end

with the following data:

+----+-------+------------------+
| id | code  | name             |
+====+=======+==================+
| 1  | visa  | Visa             |
| 2  | mc    | MasterCard       |
| 3  | disc  | Discover         |
| 4  | amex  | American Express |
+----+-------+------------------+

By adding the following line to the model:

class CardType < ActiveRecord::Base
  finder :code
end

You get the functionality of a hash-like square-bracket accessor for the model that will let you do something like:

@order.card_type = CardType[:visa]

The underlying implementation is similar to:

def CardType < ActiveRecord::Base
  def self.[](value)
    find_by_code(value)
  end
end

…except it adds a caching layer to boost performance by preventing repeated database access.

Adding the following directive:

def CardType < ActiveRecord::Base
  selectable
end

to the model gives you a class method called select_options that can be used to populate a select list like this:

<%= form.select :card_type_id, CardType.select_options %>

produces:

<input type="select" name="order[card_type_id]" id="order_card_type_id">
  <option value="1">Visa</option>
  <option value="2">MasterCard</option>
  <option value="3">Discover</option>
  <option value="4">American Express</option>
</input>

By default, this will use the id attribute as the submitted value of the option and call a display_name method (if it exists) for the displayed value of the option, falling back to the name method/attribute. Each of these can be overridden by passing a symbol attribute / method name, or a lambda that will be executed to generate the value. For (a contrived) example:

<%= form.select :card_type_id, CardType.select_options(:key => :code, :value => lambda{|card_type| card_type.name.reverse }) %>

produces:

<input type="select" name="order[card_type_id]" id="order_card_type_id">
  <option value="visa">asiV</option>
  <option value="mc">draCretsaM</option>
  <option value="disc">revocsiD</option>
  <option value="amex">sserpxE naciremA</option>
</input>

Again, the select_option results are cached for better performance.

This is a pretty small plugin that I’m using to DRY up some code in a current project I’m working on. Let me know if you have feature requests (or fork and patch it on GitHub!)