Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MongoMapper - Mapping Ruby To and From Mongo

MongoMapper - Mapping Ruby To and From Mongo

Presentation at MongoChicago 2010 on mapping MongoDB to and from Ruby using MongoMapper.

John Nunemaker
PRO

October 20, 2010
Tweet

More Decks by John Nunemaker

Other Decks in Programming

Transcript

  1. Ordered List
    John Nunemaker
    Mongo Chicago
    October 20, 2010
    MongoMapper
    Mapping Ruby To and From Mongo

    View Slide

  2. Using
    Extending
    Prophesying

    View Slide

  3. Using
    Extending
    Prophesying

    View Slide

  4. View Slide

  5. class Item
    end

    View Slide

  6. class Item
    include MongoMapper::Document
    end

    View Slide

  7. class Datum
    include MongoMapper::EmbeddedDocument
    end

    View Slide

  8. Free Stuff

    View Slide

  9. Free Stuff
    Persistence

    View Slide

  10. Free Stuff
    Persistence
    Validations [presence, length, inclusion, ...]

    View Slide

  11. Free Stuff
    Persistence
    Validations [presence, length, inclusion, ...]
    Callbacks [before/after validate, create, save, ...]

    View Slide

  12. Free Stuff
    Persistence
    Validations [presence, length, inclusion, ...]
    Callbacks [before/after validate, create, save, ...]
    Associations [many, belongs_to, one, ...]

    View Slide

  13. Free Stuff
    Persistence
    Validations [presence, length, inclusion, ...]
    Callbacks [before/after validate, create, save, ...]
    Associations [many, belongs_to, one, ...]
    Serialization [to_json]

    View Slide

  14. Persistence
    Never gonna give you up

    View Slide

  15. item = Item.create({
    :title => 'MongoSF',
    :location => 'San Fran',
    :when => Time.now
    })

    View Slide

  16. puts item.to_mongo
    {
    "_id" => ObjectID('4bd8cc5cbcd1b313b3000001'),
    "title" => "MongoSF",
    "location" => "San Fran",
    "when" => Wed Apr 28 17:01:32 -0700 2010
    }

    View Slide

  17. item = Item.new
    item[:title] = 'MongoSF'
    item[:location] = 'San Fran'
    item[:when] = Time.now
    item.save

    View Slide

  18. puts item.to_mongo
    {
    "_id" => ObjectID('4bd8cc5cbcd1b313b3000001'),
    "title" => "MongoSF",
    "location" => "San Fran",
    "when" => Wed Apr 28 17:01:32 -0700 2010
    }

    View Slide

  19. Types
    What you be baby boo?

    View Slide

  20. class Item
    include MongoMapper::Document
    key :title, String
    key :path, String
    end

    View Slide

  21. But Mongo is Schema-less?

    View Slide

  22. Think App Schema
    Instead of database schema

    View Slide

  23. Built-in Types
    Array, Binary, Boolean, Date, Float, Hash,
    Integer, Nil, ObjectId, Set, String, Time

    View Slide

  24. Custom Types
    Its shake and bake and I helped!

    View Slide

  25. class Set
    def self.to_mongo(value)
    value.to_a
    end
    def self.from_mongo(value)
    Set.new(value || [])
    end
    end

    View Slide

  26. class DowncasedString
    def self.to_mongo(value)
    value.nil? ? nil : value.to_s.downcase
    end
    def self.from_mongo(value)
    DowncasedString.to_mongo(value)
    end
    end

    View Slide

  27. class User
    include MongoMapper::Document
    key :email, DowncasedString
    end

    View Slide

  28. Typeless
    I do not know who I am

    View Slide

  29. class Foo
    include MongoMapper::Document
    key :bar
    end
    foo = Foo.new
    foo.bar = 'Some text'
    # foo.bar => "Some text"
    foo.bar = 24
    # foo.bar => 24

    View Slide

  30. Validations
    Currently using fork of validatable

    View Slide

  31. class Item
    include MongoMapper::Document
    key :title, String
    validates_presence_of :title
    end

    View Slide

  32. class Item
    include MongoMapper::Document
    key :title, String, :required => true
    end

    View Slide

  33. validates_presence_of
    validates_length_of
    validates_format_of
    validates_numericality_of
    validates_acceptance_of
    validates_confirmation_of
    validates_inclusion_of
    validates_exclusion_of

    View Slide

  34. Callbacks
    Ripped from AS2’s cold, dead fingers

    View Slide

  35. class Item
    include MongoMapper::Document
    key :title, String
    key :path, String
    key :parent_id, ObjectId
    belongs_to :parent
    before_validation :set_path
    private
    def set_path
    self.path = parent.path + title.parameterize
    end
    end

    View Slide

  36. :before_save, :after_save,
    :before_create, :after_create,
    :before_update, :after_update,
    :before_validation, :after_validation,
    :before_validation_on_create, :after_validation_on_create,
    :before_validation_on_update, :after_validation_on_update,
    :before_destroy, :after_destroy,
    :validate_on_create, :validate_on_update,
    :validate

    View Slide

  37. Scopes
    Plucky Power!

    View Slide

  38. class User
    include MongoMapper::Document
    scope :johns, where(:name => 'John')
    end
    User.johns.all
    User.johns.first

    View Slide

  39. class User
    include MongoMapper::Document
    scope :by_ages, lambda { |low, high|
    where(:age.gte => low, :age.lte => high)
    }
    end
    User.by_ages(13, 19).count
    User.by_ages(13, 19).all

    View Slide

  40. class User
    include MongoMapper::Document
    scope :teen, where(:age.gte => 13, :age.lte => 19)
    def self.by_tag(tag)
    where(:tags => tag)
    end
    end
    User.teen.by_tag('bieber').count
    User.by_tag('bieber').teen.all

    View Slide

  41. Associations
    I belong to you

    View Slide

  42. to Docs
    belongs_to, one, many, many :in

    View Slide

  43. class Account
    include MongoMapper::Document
    many :sites
    end
    class Site
    include MongoMapper::Document
    key :account_id, ObjectId
    belongs_to :account
    end

    View Slide

  44. account = Account.create(:title => 'OL', :sites => [
    Site.new(:title => 'OL', :domain => 'orderedlist.com'),
    Site.new(:title => 'RT', :domain => 'railstips.org'),
    ])

    View Slide

  45. [
    {
    '_id' => ObjectID('...'),
    'title' => 'OL',
    'domain' => 'orderedlist.com'
    'account_id' => ObjectID('...'),
    },
    {
    '_id' => ObjectID('...'),
    'title' => 'RT',
    'domain' => 'railstips.org'
    'account_id' => ObjectID('...'),
    }
    ]

    View Slide

  46. to Embedded Docs
    many, one

    View Slide

  47. class Item
    include MongoMapper::Document
    many :data
    end
    class Datum
    include MongoMapper::EmbeddedDocument
    key :key, String
    key :value
    end

    View Slide

  48. Item.create(:title => 'MongoSF', :data => [
    Datum.new(:key => 'description', :value => 'Awesome.')
    ])

    View Slide

  49. {
    '_id' => ObjectID('...'),
    'title' => 'MongoSF',
    'data' => [
    {
    '_id' => ObjectID('...'),
    'key' => 'description'
    'value' => 'Awesome.',
    }
    ]
    }

    View Slide

  50. Using
    Extending
    Prophesying

    View Slide

  51. Plugins
    Conventional way to extend

    View Slide

  52. Powered by Plugins
    MongoMapper is
    associations, callbacks, clone, descendants,
    dirty, equality, identity_map, inspect, keys,
    logger, modifiers, pagination, persistence,
    protected, rails, serialization, timestamps,
    userstamps, validations

    View Slide

  53. View Slide

  54. View Slide

  55. module MongoMapper
    module Plugins
    def plugins
    @plugins ||= []
    end
    def plugin(mod)
    extend mod::ClassMethods if mod.const_defined?(:ClassMethods)
    include mod::InstanceMethods if mod.const_defined?(:InstanceMethods)
    mod.configure(self) if mod.respond_to?(:configure)
    plugins << mod
    end
    end
    end

    View Slide

  56. module ActsAsListFu
    module ClassMethods
    def reorder(ids)
    # reorder ids...
    end
    end
    module InstanceMethods
    def move_to_top
    # move to top
    end
    end
    def self.configure(model)
    model.key :position, Integer, :default => 1
    end
    end

    View Slide

  57. class Foo
    include MongoMapper::Document
    plugin ActsAsListFu
    end
    Foo.reorder(...)
    Foo.new.move_to_top

    View Slide

  58. Good Example
    Joint: github.com/jnunemaker/joint

    View Slide

  59. class Asset
    include MongoMapper::Document
    plugin Joint
    attachment :image
    attachment :file
    end

    View Slide

  60. asset = Asset.create({
    :image => File.open('john.jpg', 'r'),
    :file => File.open('foo.txt', 'r'),
    })
    asset.image.id
    asset.image.name
    asset.image.type
    asset.image.size
    asset.image.read

    View Slide

  61. Descendant Appends
    Fancy Schmancy and Stolen

    View Slide

  62. module FancySchmancy
    def some_method
    puts 'some method'
    end
    end
    MongoMapper::Document.append_extensions(FancySchmancy)
    class Foo
    include MongoMapper::Document
    end
    Foo.some_method # puts 'some method'
    Foo.new.some_method # NoMethodError

    View Slide

  63. module FancySchmancy
    def some_method
    puts 'some method'
    end
    end
    MongoMapper::Document.append_inclusions(FancySchmancy)
    class Foo
    include MongoMapper::Document
    end
    Foo.new.some_method # puts 'some method'
    Foo.some_method # NoMethodError

    View Slide

  64. module FancySchmancy
    def some_method
    puts 'some method'
    end
    end
    class Foo
    include MongoMapper::Document
    end
    MongoMapper::Document.append_extensions(FancySchmancy)
    class Bar
    include MongoMapper::Document
    end
    Foo.some_method # puts 'some method'
    Bar.some_method # puts 'some method'

    View Slide

  65. module IdentityMapAddition
    def self.included(model)
    model.plugin MongoMapper::Plugins::IdentityMap
    end
    end
    MongoMapper::Document.append_inclusions(IdentityMapAddition)

    View Slide

  66. Using
    Extending
    Prophesying

    View Slide

  67. Active Model
    rails3 branch

    View Slide

  68. Documentation
    http://mongomapper.com

    View Slide


  69. Brian Ford @brixen
    Documentation: n.
    paradoxically repeating
    yourself so you do not
    need to repeat yourself.

    View Slide

  70. View Slide

  71. View Slide

  72. Ordered List
    Thank you!
    [email protected]
    John Nunemaker
    Mongo Chicago
    October 20, 2010
    @jnunemaker

    View Slide