views:

216

answers:

2

I created a rails model by doing

script/generate model Customer name:string address:string city:string state:string zip:integer [...]

I filled the database with 5000 customers and started building my app. Now I've realized my model isn't normalized: I often have multiple customers at the same address! If I wish to do something per-address, like, say, a mailing, this causes problems. What I'd like to have is a Address model, a Customer model, and a Mailing model.

Is there a rails way to normalize an existing model, splitting it into two models? Or should I just write a script to normalize my existing data, then generate new models accordingly?

A: 

I'm not aware of a built-in Rails way to programmatically split up your model. You'll need to write a new Address model and database update migration to get everything switched over.

Your models will likely look something like this:

class Person < ActiveRecord::Base
  has_many :addresses
end

class Address < ActiveRecord::Base
  belongs_to :person
end
macek
I expected my models to look something like this, but don't have much experience writing migrations. What would the migration look like?
petehern
A: 

You asked about what the migration would look like. Rather than cram this in a comment reply, I created a new answer for you.

script/generate model address customer_id:integer address:string city:string state:string zip:integer

class CreateAddresses < ActiveRecord::Migration
  def self.up
    create_table :addresses do |t|
      t.integer :customer_id
      t.string :address
      t.string :city
      t.string :state
      t.integer :zip_code
      t.timestamps
    end

    # move customer address fields to address table
    Customer.all.each do |c|
      Address.create({
        :customer_id => c.id,
        :address => c.address,
        :city => c.city,
        :state => c.state,
        :zip => c.zip
      })
    end

    # you'll have to write your own merge script here
    # use execute("your sql goes here...") if you can't do it with ActiveRecord methods

    # remove old customer address columns
    remove_columns(:customers, :address, :city, :state, :zip)

  end

  def self.down

    # here you will define the reverse of the self.up method

    # re-add the address columns to the user table

    # repopulate the customer table with data from the address table

    drop_table :addresses
  end
end

Resources

  1. AcitveRecord::Migration
  2. execute
macek