Skip to content

Instantly share code, notes, and snippets.

@booch
Created February 10, 2014 22:19
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save booch/8925423 to your computer and use it in GitHub Desktop.
Save booch/8925423 to your computer and use it in GitHub Desktop.
Ruby ORMs

Ruby ORMs

Abstract

Rails is really a collection of pieces that can be put together to create a web app. You can enhance or replace many of the components - how you write views, how controllers work, and how you build models. While models are built on top of ActiveRecord in the default Rails stack, you've got a lot of other choices.

In this presentation, we'll take a look at ActiveRecord and alternative ORMs. We'll discuss the pros and cons of each, and take a look at what the future will bring us.

ORMs

  • ActiveRecord
  • DataMapper
  • Sequel
  • ROM
  • Perpetuity
  • Mongoid
  • MongoMapper
  • Mince

ActiveRecord Pros

ActiveRecord is the 800-pount gorilla.

  • Ubiquitous
    • Everyone knows it
    • Lots of people improving on it
    • Plugins usually assume you're using it
    • Plenty of documentation
  • Well-tested
  • Well-understood
  • Super easy to get started
    • It's included in Rails by default
  • ARel behind the scenes

ActiveRecord Cons

  • Class inheritance
    • Not (current) idiomatic Ruby
    • Prevents a hierarchical class structure
      • TODO: Show an example where this would be useful
  • Persistence and behavior in one class
    • Violates SRP
    • Makes testing harder and slower
      • TODO: Show examples of slow tests and fast test
  • Validations are also included (another responsibility)
  • No Identity Map
    • TODO: Show example of where this is a problem
  • Have to look 2 places to find everything:
    • Attributes (fields) are declared in the schema
    • Relations are declared in the model itself

ActiveRecord Add-Ons

  • Includable ActiveRecord
    • Solves the inheritance issue
  • Annotated Models (TODO: or its replacement)
    • Kind of solves the problem of fields and relations in different places
  • Virtus::ActiveRecord or mini_record
    • Solves the problem of fields and relations in different places
  • Squeel
    • Gives a more Ruby-like API for scopes
  • Attachments (Paperclip, etc.)
  • Authentication (Devise, etc.)

DataMapper

  • Actually uses the Active Record pattern
  • Supports a lot more than just SQL on the back end
  • No further development (last updated 2012-08-27)
  • Probably the best alternative right now

  • Good documentation

  • Leverages database features (like foreign key constraints)

  • Supports almost any SQL database you can think of

  • Thread safety, connection pooling

  • Awesome feature - set a model to a subset of a table:

DB = Sequel.connect('sqlite://blog.db')
class Post < Sequel::Model
  set_primary_key [:category, :title]
  set_dataset DB[:my_posts].where(category: 'ruby').select(:category, :title, :content).order(:date)
end

ROM

  • Should be the best alternative in the future
  • Previously was called DataMapper 2
    • But has diverged a lot since the name change
  • Truly implements the Data Mapper pattern
  • Taking longer to get to 1.0 than hoped
    • Developers seem to be low-level / bottom-up types
  • Supports in-memory (PostgreSQL in the works)
  • More pieces:
    • Axiom
    • ROM::Relation
    • ROM::Mapper
    • ROM::Session
    • Model
  • Identity Map

Perpetuity

  • Worth looking at
  • Simple
  • Implements the Data Mapper patter
  • Supports MongoDB, PostgreSQL, in-memory
  • Identity Map

Mongoid and MongoMapper

  • See Sarah Mei's essay on why to avoid MongoDB in most cases
  • Mongoid
    • Pretty simple
    • Be sure to turn on MongoDB persistence!
    • Pretty stable
  • TODO: Why to avoid MongoMapper

Mince

  • Simple and light-weight (no relations)
  • Supports MongoDB, Hashy (in-memory), and DynamoDB
  • Multi-tier architecture
    • Collections and items
    • Causes some un-DRYness declaring fields
  • No further development (last updated 2013-06-07)
	require 'mince'

	class BookDataModel
	  include Mince::DataModel
	  data_collection :books
	  data_fields :title, :publisher
	end

	class Book
	  include Mince::Model
	  data_model BookDataModel
	  fields :title, :publisher
	end

	book = Book.new title: 'The World In Photographs', publisher: 'National Geographic'
	book.save

Others

  • Swift
  • ORM Adapter
    • Gives a standard API, sitting atop AR, DM, MM, or Mongoid

NoORM

  • POROs
  • Sometimes you don't need persistence for all your models
    • TODO: Show examples
  • MagLev

The Future

  • ROM will reach 1.0 and be usable in production
  • Hopefully ROM will become the go-to ORM many cases
  • Perpetuity might become useful before ROM
  • MageLev might gather a following
  • Virtus::ActiveRecord might be a stepping-stone to ROM
  • ActiveRecord will continue to improve
  • We'll learn how to better use ActiveRecord

References

@maciejczyzewski
Copy link

Thx!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment