Datamapper Railskonferenz 2009

Post on 16-Apr-2017

1.302 views 0 download

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