Datamapper Railskonferenz 2009
-
Upload
hussein-morsy -
Category
Documents
-
view
1.302 -
download
0
Transcript of Datamapper Railskonferenz 2009
DataMapper als Alternative zuActiveRecord ?
Rails-Konferenz.de 2009Hussein Morsy & Tanja Otto
1
SalesLentz::DevTeam
2
# internes Entwicklerteam von Sales-Lentz
# IBEs für Reisen, Bustickets, Eventtickets
# seit 2006 entwickeln wir mit Ruby on Rails
# Buch Ruby on Rails 2 Galileo Press
# http://railsbuch.de
# http://twitter.com/ajnato
# http://twitter.com/HusseinMorsy
Über uns
3
Wer ist ein Rails Newbie ?
4
Dan Kubb – Ruby Hero
5
Wer setzt DataMapper ein ?
6
Intro
7
ActiveRecord Intro
require 'rubygems'require 'active_record'
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => "db/shop.sqlite3")
# Tabelle manuell oder per Migration erstellen
# CREATE TABLE shoes (# ...# );
class Shoe < ActiveRecord::Baseend
Shoe.create(:brand => "Geox", :price => 52.5)
puts Shoe.first.brand# => Geox
8
DataMapper Intro
require 'rubygems'require 'dm-core'DataMapper.setup(:default, "sqlite3://db/shop.sqlite3")
class Shoe include DataMapper::Resource
property :id, Serial property :brand, String property :price, Float property :available, Booleanend
Shoe.auto_migrate!
Shoe.create(:brand => "Geox", :price => 52.5)
puts Shoe.first.brand# => Geox
9
Migrations
10
ActiveRecord Migrations
# Neue Tabelle erstellen
class CreateShoes < ActiveRecord::Migration def self.up create_table :shoes do |t| t.string :brand t.float :price
t.timestamps end end
def self.down drop_table :shoes endend
rake db:migrate
11
ActiveRecord Migrations
# Neues Feld hinzufügen
class AddAvailableToShoes < ActiveRecord::Migration def self.up add_column :shoes, :available, :boolean end
def self.down remove_column :shoes, :available endend
rake db:migrate
12
DataMapper Migrations
# Neue Tabelle erstellen
class Shoe include DataMapper::Resource property :id, Serial property :brand, String property :price, Floatend
# Tabelle shoes erstellen# Vorsicht: Daten gehen verlorenShoe.auto_migrate!
# alle Tabellen erstellen# Vorsicht: Daten gehen verlorenDataMapper.auto_migrate!
# In Datamapper gibt es auch Migrations, ähnlich wie in ActiveRecord# siehe dm-migrations
13
DataMapper Migrations
# Neues Feld hinzufügen
class Shoe include DataMapper::Resource property :id, Serial property :brand, String property :price, Float property :available, Booleanend
# Vorsicht: Daten gehen verlorenShoe.auto_migrate!
14
Extended Types
15
DataMapper Extended Types
require 'rubygems'require 'dm-core'# erweiterte Datentypenrequire 'dm-types'class Shoe include DataMapper::Resource # primitive Datentypen # ... # erweiterte Datentypen property :color, Enum[:red, :green, :blue] property :image_path, FilePathend
shoe = Shoe.newshoe.color = :redshoe.image_path = "/images/shoes.jpg"shoe.image_path.class# => Pathnameshoe.image_path.basename# => shoes.jpg
16
ActiveRecord
?Extended Types
17
Defaults
18
ActiveRecord Defaults
# Neue Tabelle erstellen
class CreateShoes < ActiveRecord::Migration def self.up create_table :shoes do |t| t.string :brand t.float :price t.float :tax, :default => 19.0
t.timestamps end end
def self.down drop_table :shoes endend
rake db:migrate
19
DataMapper Defaults
# Dynamische Default-Werte
class Shoe include DataMapper::Resource property :id, Serial property :brand, String property :price, Float
property :tax, Float, :default => 19.0end
DataMapper.auto_migrate!
my_shoe = Shoe.create(:brand => "demo", :price => 99.9)puts my_shoe.tax# => 19.0
20
DataMapper Dynamic Defaults
# Dynamische Default-Werte
class Shoe include DataMapper::Resource property :id, Serial property :brand, String property :price, Float property :tax, Float, :default => 19 property :sale, Float, :default => Proc.new { |r, p| r.price * 0.5 }end
DataMapper.auto_migrate!
my_shoe = Shoe.create(:brand => "demo", :price => 99.9)puts my_shoe.sale# => 49.95
21
ActiveRecord
?Dynamic Defaults
22
Validations
23
ActiveRecord Validations
# Model ohne Validierung
class Woman < ActiveRecord::Baseend
24
ActiveRecord Validations
# Model mit Validierung
class Woman < ActiveRecord::Base validates_presence_of :name validates_length_of :title, :within => 2..20 validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i validates_uniqueness_of :emailend
25
DataMapper Validations
# Model ohne Validierung
class Woman include DataMapper::Resource property :id, Serial property :name, String property :title, String property :email, String
end
26
DataMapper Validations
# Model mit Validierung
class Woman include DataMapper::Resource property :id, Serial property :name, String, :nullable => false property :title, String, :length => 2..20 property :email, String, :nullable => false, :format => :email_address, :unique => true
end
27
Identity Map
28
ActiveRecord Identity Map
Shoe.first.eql? Shoe.first
# => false
29
DataMapper Identity Map
Shoe.first.eql? Shoe.first
# => true
30
Lazy Loading
31
DataMapper Lazy Loading
class Shoe include DataMapper::Resource
property :id, Serial property :brand, String property :price, Float property :short_description, String, :length => 255, :lazy => true property :description, Text # default :lazy => trueend
# SELECT id, brand, price from shoes where id=1my_shoe = Shoe.get(1)
# SELECT short_description from shoes where id=1my_shoe.short_description
# SELECT description from shoes where id=1my_shoe.description
32
DataMapper Lazy Loading
class Shoe include DataMapper::Resource
property :id, Serial property :brand, String property :price, Float property :short_description, String, :length => 255, :lazy => [:details] property :description, Text, :lazy => [:details]end
# SELECT id, brand, price from shoes where id=1my_shoe = Shoe.get(1)
# SELECT short_description,description from shoes where id=1my_shoe.short_description
# Keine Datenbankabfragemy_shoe.description
33
ActiveRecord
?Lazy Loading
34
ActiveRecord Lazy Loading
class Shoe < ActiveRecord::Baseend
my_shoe = Shoe.all(:select => "id, brand, price").firstputs my_shoe.brand
my_shoe.description # => Exception
puts Shoe.first(:select => "id,description")
35
Keys
36
ActiveRecord Keys
# Primary Keys automatisch in Migration# Immer Integer
37
DataMapper Keys
class Woman include DataMapper::Resource property :id, Integer, :serial => true # ...end
Woman.get(7)
38
DataMapper Keys
# Kurzform
class Woman include DataMapper::Resource property :id, Serial # ...end
Woman.get(7)
39
DataMapper Keys
# Natürlicher Key
class Woman include DataMapper::Resource property :steuer_identifikationsnummer, :key => trueend
Woman.get("i2930d980324")
40
DataMapper Keys
# Composite Keys
class Woman include DataMapper::Resource property :steuer_identifikationsnummer, :key => true property :pass_nr, :key => trueend
Woman.get("i2930d980324","949823902-X-234s")
41
Search
42
ActiveRecord Search
class Shoe < ActiveRecord::Baseend
# the ActiveRecord-SQL-Style Shoe.find(:all, :conditions => ["brand=? AND price < ?", "Geox", 130.0])
# brand = GeoxShoe.all(:conditions => {:brand => "Geox"})
# brand != GeoxShoe.all(:conditions => ["brand IS NOT ?", "Geox"])
# brand IS NOT NULLShoe.all(:conditions => "brand IS NOT NULL")
# brand like "G%"Shoe.all(:conditions => "brand LIKE G%")
# brand = "Geox" OR brand= "Converse"Shoe.all(:conditions => {:brand => ["Geox", "Converse"]})
43
DataMapper Search
class Shoe include DataMapper::Resource property :id, Serial property :brand, String property :price, Floatend
DataMapper.auto_migrate!
# the ActiveRecord-SQL-Style Shoe.all(:conditions => ["brand=? AND price < ?", "Geox", 130.0])
44
DataMapper Search
# the ActiveRecord-SQL-Style Shoe.all(:conditions => ["brand=? AND price < ?", "Geox", 130.0])
# the DataMapper-StyleShoe.all(:brand => "Geox", :price.lt => 130.0)
# brand != GeoxShoe.all(:brand.not => "Geox")
# brand IS NOT NULLShoe.all(:brand.not => nil)
# brand like "G%"Shoe.all(:brand.like => "G%")
# price <= 60.0Shoe.all(:price.lte => 60.0)
# brand = "Geox" OR brand= "Converse"Shoe.all(:brand => ["Geox", "Converse"])
45
Named Scope
46
ActiveRecord Named Scope
class Shoe < ActiveRecord::Base named_scope :available, :conditions => ['available = ?', true] named_scope :cheaper, lambda { |max_price| { :conditions => ['price < ?', max_price] } }end
Shoe.available.cheaper(20)
47
DataMapper Named Scope
class Shoe include DataMapper::Resource property :id, Serial property :brand, String property :price, Float property :available, Boolean def self.available all(:available => true) end def self.cheaper(max_price) all(:price.lt => max_price) endend
Shoe.available.cheaper(210.0)
48
Associations
49
ActiveRecord Associations
class Woman has_many :shoesend
class Shoe belongs_to :woman has_many :categories, :through => :categorisationsend
50
DataMapper Associations
class Woman include DataMapper::Resource property :id, Serial property :name, String has n, :shoesend
class Shoe include DataMapper::Resource property :id, Serial property :brand, String property :price, Float property :woman_id, Integer
belongs_to :woman has n,:categories, :through => :categorisationsend
51
Timestamps
52
ActiveRecord Timestamps
# Neue Tabelle erstellen mit einer Migrationclass CreateShoes < ActiveRecord::Migration def self.up create_table :shoes do |t| t.string :brand t.float :price
t.timestamps end end
def self.down drop_table :shoes endend
# Modelclass Shoe < ActiveRecord::Baseend
my_shoe = Shoe.create(:brand => "demo", :price => 99.9)puts my_shoe.created_atputs my_shoe.updated_at
53
DataMapper Timestamps
require 'initdb'
class Shoe include DataMapper::Resource property :id, Serial property :brand, String property :price, Float property :created_at, DateTime property :updated_at, DateTimeend
DataMapper.auto_migrate!
my_shoe = Shoe.create(:brand => "demo", :price => 99.9)puts my_shoe.created_at# => nil
54
DataMapper Timestamps
require 'initdb'require 'dm-timestamps'
class Shoe include DataMapper::Resource property :id, Serial property :title, String property :price, Float property :created_at, DateTime property :updated_at, DateTimeend
DataMapper.auto_migrate!
my_shoe = Shoe.create(:title => "demo", :price => 99.9)puts my_shoe.created_at# => 2009-08-30T04:29:36+00:00
55
DataMapper Timestamps
require 'initdb'require 'dm-timestamps'
class Shoe include DataMapper::Resource property :id, Serial property :title, String property :price, Float timestamps :created_at, :updated_atend
DataMapper.auto_migrate!
my_shoe = Shoe.create(:title => "demo", :price => 99.9)puts my_shoe.created_at# => 2009-08-30T04:29:36+00:00
56
DataMapper Timestamps
require 'initdb'require 'dm-timestamps'
class Shoe include DataMapper::Resource property :id, Serial property :title, String property :price, Float timestamps :atend
DataMapper.auto_migrate!
my_shoe = Shoe.create(:title => "demo", :price => 99.9)puts my_shoe.created_at# => 2009-08-30T04:29:36+00:00
57
Multi Databases
58
ActiveRecord
?Multi Databases
59
DataMapper Multi Databases
DataMapper.setup(:default, "sqlite3:///#{Dir.pwd}/db/crm.sqlite3")DataMapper.setup(:shop, "sqlite3:///#{Dir.pwd}/db/shop.sqlite3")
class Woman include DataMapper::Resource property :id, Serial property :name, Stringend
class Shoe include DataMapper::Resource def self.default_repository_name :shop end
property :id, Serial property :brand, String property :price, Float end
60
Naming Conventions
61
ActiveRecord Naming Conventions
class Shoe < ActiveRecord::Base set_table_name "tbl_Shoe"end
class Woman < ActiveRecord::Base set_table_name "tbl_Woman"end
62
DataMapper Naming Conventions
class Shoe include DataMapper::Resource storage_names[:default] = 'tbl_Shoe' #....end
class Woman include DataMapper::Resource storage_names[:default] = 'tbl_Woman' #....end
63
DataMapper Naming Conventions
repository(:default).adapter.resource_naming_convention = lambda { |klass| "tbl_#{klass.camel_case}" }
class Shoe include DataMapper::Resource # ....end
class Woman include DataMapper::Resource #....end
64
Legacy Databases
65
ActiveRecord
?Legacy Databases
66
DataMapper Legacy Databases
class Woman include DataMapper::Resource storage_names[:default] = 'tbl_woman' property :id, String, :field => "NR", :key => true property :firstname, String, :field => "VORNAME" property :title, String, :field => "ANREDE" property :email, String, :nullable => false, :format => :email_address, :unique => trueend
# Im Gegensatz zu ActiveRecord werden nur die angegebenen Felder gelesen
67
Adapter
68
ActiveRecord Adapter
MySQL
PostgreSQL
SQLite
Oracle
69
DataMapper Adapter
MySQL
PostgreSQL
SQLite
Oracle
IMAPYAML ...
70
Rails 3
71
Fazit
72
one more thing...
73
74
Solo Division Winner: Jacques Crocker
75
mit DataMapper gemacht!
76
http://github.com/merbjedi/alertme_tv
77
78