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.

E13c31390e0369fcd5972292ce0e7b92?s=128

John Nunemaker

October 20, 2010
Tweet

Transcript

  1. Ordered List John Nunemaker Mongo Chicago October 20, 2010 MongoMapper

    Mapping Ruby To and From Mongo
  2. Using Extending Prophesying

  3. Using Extending Prophesying

  4. None
  5. class Item end

  6. class Item include MongoMapper::Document end

  7. class Datum include MongoMapper::EmbeddedDocument end

  8. Free Stuff

  9. Free Stuff Persistence

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

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

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

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

    validate, create, save, ...] Associations [many, belongs_to, one, ...] Serialization [to_json]
  14. Persistence Never gonna give you up

  15. item = Item.create({ :title => 'MongoSF', :location => 'San Fran',

    :when => Time.now })
  16. puts item.to_mongo { "_id" => ObjectID('4bd8cc5cbcd1b313b3000001'), "title" => "MongoSF", "location"

    => "San Fran", "when" => Wed Apr 28 17:01:32 -0700 2010 }
  17. item = Item.new item[:title] = 'MongoSF' item[:location] = 'San Fran'

    item[:when] = Time.now item.save
  18. puts item.to_mongo { "_id" => ObjectID('4bd8cc5cbcd1b313b3000001'), "title" => "MongoSF", "location"

    => "San Fran", "when" => Wed Apr 28 17:01:32 -0700 2010 }
  19. Types What you be baby boo?

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

    end
  21. But Mongo is Schema-less?

  22. Think App Schema Instead of database schema

  23. Built-in Types Array, Binary, Boolean, Date, Float, Hash, Integer, Nil,

    ObjectId, Set, String, Time
  24. Custom Types Its shake and bake and I helped!

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

    []) end end
  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
  27. class User include MongoMapper::Document key :email, DowncasedString end

  28. Typeless I do not know who I am

  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
  30. Validations Currently using fork of validatable

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

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

    end
  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

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

  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
  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
  37. Scopes Plucky Power!

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

    User.johns.all User.johns.first
  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
  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
  41. Associations I belong to you

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

  43. class Account include MongoMapper::Document many :sites end class Site include

    MongoMapper::Document key :account_id, ObjectId belongs_to :account end
  44. account = Account.create(:title => 'OL', :sites => [ Site.new(:title =>

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

    'orderedlist.com' 'account_id' => ObjectID('...'), }, { '_id' => ObjectID('...'), 'title' => 'RT', 'domain' => 'railstips.org' 'account_id' => ObjectID('...'), } ]
  46. to Embedded Docs many, one

  47. class Item include MongoMapper::Document many :data end class Datum include

    MongoMapper::EmbeddedDocument key :key, String key :value end
  48. Item.create(:title => 'MongoSF', :data => [ Datum.new(:key => 'description', :value

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

    { '_id' => ObjectID('...'), 'key' => 'description' 'value' => 'Awesome.', } ] }
  50. Using Extending Prophesying

  51. Plugins Conventional way to extend

  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
  53. None
  54. None
  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
  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
  57. class Foo include MongoMapper::Document plugin ActsAsListFu end Foo.reorder(...) Foo.new.move_to_top

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

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

    end
  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
  61. Descendant Appends Fancy Schmancy and Stolen

  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
  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
  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'
  65. module IdentityMapAddition def self.included(model) model.plugin MongoMapper::Plugins::IdentityMap end end MongoMapper::Document.append_inclusions(IdentityMapAddition)

  66. Using Extending Prophesying

  67. Active Model rails3 branch

  68. Documentation http://mongomapper.com

  69. “ Brian Ford @brixen Documentation: n. paradoxically repeating yourself so

    you do not need to repeat yourself.
  70. None
  71. None
  72. Ordered List Thank you! john@orderedlist.com John Nunemaker Mongo Chicago October

    20, 2010 @jnunemaker