Rails in the Enterprise: Off the Beaten Track Alex Rothenberg http://alexrothenberg.com @alexrothenberg Pat Shaughnessy http://patshaughnessy.net @patshaughnessy2 Thursday, July 22, 2010
Thursday, July 22, 2010
Thursday, July 22, 2010
Thursday, July 22, 2010
Thursday, July 22, 2010
Using Rails When ... sharing a development database there was no documented way to create a new database our existing database was not built with Rails in mind the database schema is hard to work with when you find application code in the database Thursday, July 22, 2010
Problem 1: Sharing a development database Thursday, July 22, 2010
From: ... To: All Developers Cc: ... Date: 07/06/2010 09:47 AM Subject: Dev/QA Databases unavailable. Hi All, This is to inform you that all the databases on Dev/QA servers are down due to issues in UNIX file systems. Please find the following list of servers are impacted - oradbdev-ux01 - oradbdev-ux02 - oradbdev-ux03 - oradbqa-ux01 - oradbqa-ux02 Thursday, July 22, 2010
Great tutorials for installing Oracle on a Mac: Mac OS X Leopard: http://blog.rayapps.com/2009/04/12/how-to-install-oracle- database-10g-on-mac-os-x-intel/ Mac OS X Snow Leopard: http://blog.rayapps.com/2009/09/14/how-to-install-oracle- database-10g-on-mac-os-x-snow-leopard/ Thursday, July 22, 2010
Oracle install kits Oracle 11g: http://www.oracle.com/technology/software/products/ database/index.html Oracle XE (for Linux & Windows only) http://www.oracle.com/technology/software/products/ database/xe/index.html Thursday, July 22, 2010
~ pat$ sqlplus dev/dev@orcl SQL*Plus: Release 10.2.0.4.0 - Production on Wed Jul 14 22:12:06 2010 SQL> exit ~ pat$ sqlplus test/test@orcl SQL*Plus: Release 10.2.0.4.0 - Production on Wed Jul 14 22:12:06 2010 SQL> Thursday, July 22, 2010
Problem 2: There was no documented way to create the database Thursday, July 22, 2010
class CreatePeople < ActiveRecord::Migration def self.up create_table :people do |t| t.string :name t.timestamps end end def self.down drop_table :people end end Thursday, July 22, 2010
my_app pat$ rake db:migrate (in /Users/pat/my_app) my_app pat$ Thursday, July 22, 2010
ActiveRecord::Schema.define(:version => ...) do create_table "people", :force => true do |t| t.string "name" t.datetime "created_at" t.datetime "updated_at" end # Lots more Enterprise crap deleted here... end Thursday, July 22, 2010
class MigrationZero < ActiveRecord::Migration def self.up end def self.down end end Thursday, July 22, 2010
class MigrationZero < ActiveRecord::Migration def self.up create_table "people", :force => true do |t| t.string "name" t.datetime "created_at" t.datetime "updated_at" end # Lots more Enterprise crap pasted here... end Thursday, July 22, 2010
my_app pat$ rake db:populate (in /Users/pat/my_app) Deleting existing people... Loading new people... 43 people added. etc... Thursday, July 22, 2010
Problem 3: Our existing database was not built with Rails in mind Thursday, July 22, 2010
class Person < ActiveRecord::Base end Thursday, July 22, 2010
class Person < ActiveRecord::Base set_table_name :psn_person set_primary_key :personid end Thursday, July 22, 2010
class Person < ActiveRecord::Base set_table_name :psn_person set_primary_key :personid has_many :addresses, :foreign_key => :personid end Thursday, July 22, 2010
Thursday, July 22, 2010
Thursday, July 22, 2010
Legacy Data Gem Install: gem install legacy_data Source: http://github.com/alexrothenberg/legacy_data Thursday, July 22, 2010
my_app pat$ script/generate models_from_tables analyzing psn_perdiem => PsnPerdiem analyzing psn_person => PsnPerson analyzing psn_personal_info => PsnPersonalInfo etc... Thursday, July 22, 2010
class Person < ActiveRecord::Base set_table_name :psn_person set_primary_key :personid has_many :addresses, :foreign_key => :personid validates_presence_of :first_name validates_uniqueness_of :employee_id end Thursday, July 22, 2010
• User friendly error messages • Accessible to most of development team • Easier to write tests Thursday, July 22, 2010
Problem 4: The database schema was hard to work with Thursday, July 22, 2010
SELECT personid, first_name, last_name, ... FROM psn_person Thursday, July 22, 2010
SELECT personid, first_name, last_name FROM psn_person INNER JOIN psn_person_extra ON psn_person... INNER JOIN psn_person_career ON psn_person... INNER JOIN psn_person_email ON psn_person... INNER JOIN pik_position ON psn_person... INNER JOIN pik_yes_no ON psn_person... ...and many more... Thursday, July 22, 2010
class Person < ActiveRecord::Base has_one :person_extra has_one :person_career has_one :person_email belongs_to :pik_position belongs_to :pik_yes_no # And many other associations too end Thursday, July 22, 2010
Thursday, July 22, 2010
SELECT personid, first_name, last_name FROM psn_person INNER JOIN psn_person_extra ON psn_person... INNER JOIN psn_person_career ON psn_person... INNER JOIN psn_person_email ON psn_person... INNER JOIN pik_position ON psn_person... INNER JOIN pik_yes_no ON psn_person... SELECT id, first_name, last_name, ... FROM people Thursday, July 22, 2010
class CreatePeopleView < ActiveRecord::Migration def self.up execute <<-END_SQL CREATE VIEW people AS SELECT personid AS id, ... FROM psn_person INNER JOIN ... ... END_SQL end def self.down execute "DROP VIEW people" end end Thursday, July 22, 2010
class Person < ActiveRecord::Base default_scope :readonly=>true end Thursday, July 22, 2010
require 'spec_helper' describe Person do it "should ..." do Factory :person, :name => 'hilda' Factory :person, :name => 'fredo' # Do something with people # and assert on result ... end end Thursday, July 22, 2010
Thursday, July 22, 2010
Problem 5: We found legacy code in our database Thursday, July 22, 2010
Thursday, July 22, 2010
PROCEDURE MergeAddress ( pCorrectPersonID IN pkgGlobal.tyID, pDuplicatePersonId IN pkgGlobal.tyId ) IS type tyAddressTable IS TABLE OF pkgAddressBase.tyData INDEX BY binary_integer; IDTable tyIDTable; EmptyTable tyAddressTable; CorrectTable tyAddressTable; DuplicateTable tyAddressTable; i INTEGER := 0; primary_count INTEGER := 0; primary_count_for_delete INTEGER := 0; CID pkgGlobal.tyID; SQLStr pkgGlobal.tyData; -- PROCEDURE FillTable ( pDuplicatePersonId IN pkgGlobal.tyId, pTable OUT tyAddressTable ) IS aToken pkgGlobal.tyId; CURSOR c1 IS SELECT ADDRESSID, PERSONID, ADDRESSTYPEID, ISPRIMARY, STREET1, STREET2, STREET3, STREET4, CITY, STATEPROVINCEID, POSTALCODE, COUNTRYID, SYSTEMNOTE, ADDRESSNOTE FROM tbAddress WHERE PersonID = pDuplicatePersonID; BEGIN FOR r IN c1 LOOP pTable(r.AddressId).AddressId := r.AddressID; pTable(r.AddressId).PersonID := r.PersonID; pTable(r.AddressId).AddressTypeId := r.AddressTypeId; pTable(r.AddressId).IsPrimary := r.IsPrimary; pTable(r.AddressId).Street1 := r.Street1; pTable(r.AddressId).Street2 := r.Street2; pTable(r.AddressId).Street3 := r.Street3; pTable(r.AddressId).Street4 := r.Street4; pTable(r.AddressId).city := r.city; pTable(r.AddressId).StateProvinceId := r.StateProvinceId; pTable(r.AddressId).postalCode := r.postalCode; pTable(r.Addressid).countryId := r.countryId; pTable(r.Addressid).AddressNote := r.addressNote; pTable(r.Addressid).systemNote := r.systemNote; END LOOP; END; Thursday, July 22, 2010
Recommend
More recommend