rails

Rails migration with a list of all United States

How many times have you created web applications that use addresses? Since I felt like I wasted the entire 10 minutes it took me to type out this state list, I figured I’d share it with everyone so that their time wasn’t equally wasted. Enjoy.

Run this command:

ruby script/generate model State

And put this in db/migrate/XXX_create_states.rb:

class CreateStates < ActiveRecord::Migration
  def self.up
    create_table :states do |t|
      t.column :name, :string
      t.column :abbreviation, :string
    end
 
    State.create :name => 'Alabama', :abbreviation => 'AL'
    State.create :name => 'Alaska', :abbreviation => 'AK'
    State.create :name => 'Arizona', :abbreviation => 'AZ'
    State.create :name => 'Arkansas', :abbreviation => 'AR'
    State.create :name => 'California', :abbreviation => 'CA'
    State.create :name => 'Colorado', :abbreviation => 'CO'
    State.create :name => 'Connecticut', :abbreviation => 'CT'
    State.create :name => 'Delaware', :abbreviation => 'DE'
    State.create :name => 'District of Columbia', :abbreviation => 'DC'
    State.create :name => 'Florida', :abbreviation => 'FL'
    State.create :name => 'Georgia', :abbreviation => 'GA'
    State.create :name => 'Hawaii', :abbreviation => 'HI'
    State.create :name => 'Idaho', :abbreviation => 'ID'
    State.create :name => 'Illinois', :abbreviation => 'IL'
    State.create :name => 'Indiana', :abbreviation => 'IN'
    State.create :name => 'Iowa', :abbreviation => 'IA'
    State.create :name => 'Kansas', :abbreviation => 'KS'
    State.create :name => 'Kentucky', :abbreviation => 'KY'
    State.create :name => 'Louisiana', :abbreviation => 'LA'
    State.create :name => 'Maine', :abbreviation => 'ME'
    State.create :name => 'Maryland', :abbreviation => 'MD'
    State.create :name => 'Massachutsetts', :abbreviation => 'MA'
    State.create :name => 'Michigan', :abbreviation => 'MI'
    State.create :name => 'Minnesota', :abbreviation => 'MN'
    State.create :name => 'Mississippi', :abbreviation => 'MS'
    State.create :name => 'Missouri', :abbreviation => 'MO'
    State.create :name => 'Montana', :abbreviation => 'MT'
    State.create :name => 'Nebraska', :abbreviation => 'NE'
    State.create :name => 'Nevada', :abbreviation => 'NV'
    State.create :name => 'New Hampshire', :abbreviation => 'NH'
    State.create :name => 'New Jersey', :abbreviation => 'NJ'
    State.create :name => 'New Mexico', :abbreviation => 'NM'
    State.create :name => 'New York', :abbreviation => 'NY'
    State.create :name => 'North Carolina', :abbreviation => 'NC'
    State.create :name => 'North Dakota', :abbreviation => 'ND'
    State.create :name => 'Ohio', :abbreviation => 'OH'
    State.create :name => 'Oklahoma', :abbreviation => 'OK'
    State.create :name => 'Oregon', :abbreviation => 'OR'
    State.create :name => 'Pennsylvania', :abbreviation => 'PA'
    State.create :name => 'Rhode Island', :abbreviation => 'RI'
    State.create :name => 'South Carolina', :abbreviation => 'SC'
    State.create :name => 'South Dakota', :abbreviation => 'SD'
    State.create :name => 'Tennessee', :abbreviation => 'TN'
    State.create :name => 'Texas', :abbreviation => 'TX'
    State.create :name => 'Utah', :abbreviation => 'UT'
    State.create :name => 'Vermont', :abbreviation => 'VT'
    State.create :name => 'Virginia', :abbreviation => 'VA'
    State.create :name => 'Washington', :abbreviation => 'WA'
    State.create :name => 'West Virginia', :abbreviation => 'WV'
    State.create :name => 'Wisconsin', :abbreviation => 'WI'
    State.create :name => 'Wyoming', :abbreviation => 'WY'
 
  end
 
  def self.down
    drop_table :states
  end
end

rails
ruby

Comments (4)

Permalink

Rails’ attachment_fu, :thumbnail_class and you

I was having a bit of trouble with attachment_fu that took a while to figure out, so I thought I’d post my solution for the next person.

I have a Photo model that I’m using to store pictures. Since attachment_fu will automatically resize, create thumbnails, and store pictures on the file system, it was an easy choice to use it. The things I found I didn’t like about it:

  1. It stores thumbnails as separate records inside the photos table. This means you have to check if thumbnail.nil? each time you display the pictures, and you’ll have to check parent_id.nil? to count your photos.
  2. You can’t use your own model validations. For example, I wanted to use
validates_presence_of :name
validates_presence_of :description

But I’d always get validation errors because attachment_fu tries to save the thumbnail attributes when it creates or resizes a thumbnail. As you can imagine, this is a major problem.

:thumbnail_class to the rescue

Mike Clark’s attachment_fu blog post mentions that you can use the :thumbnail_class argument to separate your model validations and attachment_fu’s validations. Here’s how to do it:

class Photo < ActiveRecord::Base
  has_many :thumbnails, :foreign_key => 'parent_id'
 
  has_attachment  :storage => :file_system,
                          :content_type => :image,
                          :max_size => 10.megabytes,
                          :resize_to => '640x480',
                          :thumbnails => { :thumb => '100x100' },
                          :thumbnail_class => Thumbnail
 
  # Validations
  validates_presence_of :name
  validates_presence_of :description
end
 
class Thumbnail < ActiveRecord::Base
  belongs_to :photo, :foreign_key => 'parent_id'
 
  has_attachment  :storage => :file_system,
                  :content_type => :image
end

The killer for me initially was that I wasn’t specifying has_attachment in the Thumbnail model. I always got this error:

undefined method `temp_path=' for #thumbnail:0xb69a9514

So save yourself by putting has_attachment in both models. Make sure to define any attachment_fu arguments in your Photo model, and leave the Thumbnail model bare. You’ll also want to make sure you have the normal attachment_fu schema in both models:

      t.column :parent_id,  :integer
      t.column :content_type, :string
      t.column :filename, :string
      t.column :thumbnail, :string
      t.column :size, :integer
      t.column :width, :integer
      t.column :height, :integer

I’ve found that everything seems to be working as normal going this route. My model validations work and the thumbnails are not polluting the photos table. If you want to find the Photo for a particular Thumbnail, keep in mind that parent_id now refers to the id in the Photo model:

t = Thumbnail.find ....  # find your thumbnail
p = Photo.find(t.parent_id)

And for the ultimate ease-of-use relationship, just use:

t = Thumbnail.find ....  # find your thumbnail
p = t.photo               # get a photo
p.thumbnails              # get all thumbnails

This works since we defined the has_many relationship in the model.

Let me know if you have any problems with this method or if it helped you!

rails
ruby

Comments (6)

Permalink

How to create a lookup table in Ruby on Rails

I’m a big fan of the Rails way, but sometimes the simple things get you. I like to set up “lookup tables” in Rails, ie. tables in the database that hold commonly used, (often) fixed values. For example, if I have a Car model, I might want to define a Car type model. This would have two purposes:

  1. Give me the ability to associate a type with the Car model (ie. Car.type => ’sport’)
  2. Pre-load common values into the database (ie. sport, coupe, sedan, etc)

Continue Reading »

rails
ruby

Comments (0)

Permalink

New version of Rails available

If you didn’t know already, there is a new version of Rails out there.

And I’m not referring to the Rails 2.0 preview. This is Rails 1.2.5, which contains fixes for a JSON XSS (cross-site scripting) vulnerability. I’m not horribly familiar with the details, but the site does say that you don’t have to worry about it if you’re not using JSON. Probably a good idea to upgrade anyway.

rails

Comments (0)

Permalink

Rails’ ruby script/console has tab completion!

While I recently found out about Ruby’s ‘methods’ method, I also found that Rails’ “ruby script/console” will do tab completion:

>> a = Array.new
=> []
>> a.
Display all 157 possibilities? (y or n)
a.fetch                              a.method                             a.slice
a.__id__                             a.fill                               a.methods                            a.slice!
a.__send__                           a.find                               a.min                                a.sort
a.all?                               a.find_all                           a.nil?                               a.sort!
a.any?                               a.first                              a.nitems                             a.sort_by
a.assoc                              a.flatten                            a.object_id                          a.split
a.at                                 a.flatten!                           a.pack                               a.subclasses_of
a.b64encode                          a.freeze                             a.partition                          a.sum
a.blank?                             a.frozen?                            a.pop                                a.suppress
a.class                              a.gem                                a.pretty_inspect                     a.taguri
a.clear                              a.grep                               a.pretty_print                       a.taguri=
a.clone                              a.group_by                           a.pretty_print_cycle                 a.taint
a.collect                            a.hash                               a.pretty_print_inspect               a.tainted?
a.collect!                           a.id                                 a.pretty_print_instance_variables    a.to_a
a.compact                            a.in_groups_of                       a.private_methods                    a.to_ary
a.compact!                           a.include?                           a.protected_methods                  a.to_default_s
a.concat                             a.index                              a.public_methods                     a.to_formatted_s
a.copy_instance_variables_from       a.index_by                           a.push                               a.to_json
a.daemonize                          a.indexes                            a.rassoc                             a.to_param
a.dclone                             a.indices                            a.reject                             a.to_s
a.decode64                           a.inject                             a.reject!                            a.to_sentence
a.decode_b                           a.insert                             a.remove_subclasses_of               a.to_set
a.delete                             a.inspect                            a.replace                            a.to_xml
a.delete_at                          a.instance_eval                      a.require                            a.to_yaml
a.delete_if                          a.instance_exec                      a.require_gem                        a.to_yaml_properties
a.detect                             a.instance_of?                       a.require_library_or_gem             a.to_yaml_style
a.display                            a.instance_values                    a.respond_to?                        a.transpose
a.dup                                a.instance_variable_get              a.returning                          a.type
a.each                               a.instance_variable_set              a.reverse                            a.uniq
a.each_index                         a.instance_variables                 a.reverse!                           a.uniq!
a.each_with_index                    a.is_a?                              a.reverse_each                       a.unloadable
a.empty?                             a.join                               a.rindex                             a.unshift
a.enable_warnings                    a.kind_of?                           a.select                             a.untaint
a.encode64                           a.last                               a.send                               a.values_at
a.entries                            a.length                             a.shift                              a.with_options
a.eql?                               a.load                               a.silence_stderr                     a.yaml_initialize
a.equal?                             a.map                                a.silence_stream                     a.zip
a.extend                             a.map!                               a.silence_warnings
a.extend_with_included_modules_from  a.max                                a.singleton_methods
a.extended_by                        a.member?                            a.size

Unfortunately the same thing doesn’t work for the irb. Of course you can always

a.methods.sort

to see the same information.

rails
ruby

Comments (0)

Permalink

Convert has_and_belongs_to_many to a has_many :through association

So there are plenty of resources out there to learn how to use has_many :through associations.

I followed them over and over again but couldn’t get my code to work. I knew I had the basic structure setup correctly, since the examples are pretty straightforward, and the concept is not difficult. My has_and_belongs_to_many code originally looked like this:

class Soda < ActiveRecord::Base
  has_and_belongs_to_many :distributors
end
 
class Distributor < ActiveRecord::Base
  has_and_belongs_to_many :sodas
end

Of course there was also a many-to-many join table migration:

class DistributorsSodasJoinTable < ActiveRecord::Migration
  def self.up
    create_table :distributors_sodas, :id => false do |t|
      t.column :soda_id, :int
      t.column :distributor_id, :int
    end
  end  
 
  def self.down
    drop_table :distributors_sodas
  end
end

This works quite nicely:

>> Soda.find(1).distributors
=> []

Later found that I needed to add attributes in the join table to associate extra fields on the Distributors <-> Sodas relationship. has_and_belongs_to_many does not have a Rails way to access those extra fields in the join table. I’ve successfully done it through SQL, but much guilt and remorse lead me to finally learn has_many :through.

This was my best initial attempt:

class Soda < ActiveRecord::Base
  has_many :distributors_sodas
  has_many :distributors, :through =>; :distributors_sodas
end
 
class Distributor < ActiveRecord::Base
  has_many :distributors_sodas
  has_many :distributors, :through => :distributors_sodas
end
 
class DistributorsSodas < ActiveRecord::Base
  belongs_to :soda
  belongs_to :distributor
end

All goes well until I try to do a quick test:

>> Soda.find(1).distributors
NameError: uninitialized constant Soda::DistributorsSoda
...
        from (irb):4

Umm… what? I never tried to instantiate an object of the type Soda::DistributorsSoda. Instead, I was simply trying to use the DistributorsSodas ActiveRecord object, right?

It turns out that has_many :through (apparently) can’t handle using the join tables created by has_and_belongs_to_many. Its just a naming issue - has_many :through will work fine using a one-to-many join table like distributor_sodas (note the missing ’s’ on distributor). If you need a many-to-many join, you have to rename the table to fix the (pluralization?) problem. I deleted the DistributorsSodas model and created the Store model.

class Soda < ActiveRecord::Base
  has_many :stores
  has_many :distributors, :through => :stores
end
 
class Distributor < ActiveRecord::Base
  has_many :stores
  has_many :sodas, :through => :stores
end
 
class Store < ActiveRecord::Base
  belongs_to :soda
  belongs_to :distributor
end

This proved a much better result:

>> Soda.find(1).distributors
=> []

In the end, the association naming convention actually make more sense. I was bummed to have to change the table/model names though.

Please comment if you know how to create the association without changing the model name.

rails

Comments (6)

Permalink

Installing Mongrel on Ubuntu Feisty with rubygems

When I recently re-installed Ubuntu 7.04 (Feisty), I found that I couldn’t build the native fastthread gem (a required dependency). If you get this error:

Building native extensions. This could take a while...
extconf.rb:1:in `require': no such file to load -- mkmf (LoadError)
from extconf.rb:1


ERROR: While executing gem ... (RuntimeError)
ERROR: Failed to build gem native extension.
Gem files will remain installed in /var/lib/gems/1.8/gems/fastthread-1.0 for inspection.

then you need the ruby development libraries and the build-essential package. I’ve found that these commands will make sure mongrel (and rails) is installed correctly:

$ sudo apt-get install ruby1.8-dev rubygems build-essential rails
$ sudo gem install mongrel --include-dependencies

linux
rails
ruby

Comments (0)

Permalink