Rails and alternative ORMs


Published on

Most Rails users are familiar with ActiveRecord. But what does that mean? What is ActiveRecord's approach to object relational mapping? And what are the alternatives?

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

  • So ... Why use an ORM?
  • Because your database and your OO code are unlike things. Different paradigms.

    So in a sense, any time you use a relational DB + OO, you’re going to do some sort of object relational mapping.

    May be formal or informal.

  • So data types are not identical
  • Your DB has a formal definition independent of the use of the data.
  • This is a big one.

    In OO, you follow references - an object can “point” to another object, and so on.

    In SQL, you logically join sets of data together.
  • Any bit of data can be joined to any other bit.

    In OO, ideal is to hide as much as you can and only expose a public interface.
  • declarative vs. active - declare that certain kinds of data are acceptable, vs. actively checking at certain points in time.
  • SQL doesn’t directly have a concept of inheritance. Fundamental to OO.

  • Finally, different purposes.

    Define structure for data (and hold that data)


    Doing something
  • So basically, ORM are translators between unlike things. Like any translation,
  • this isn’t going to be perfectly smooth, and there will always be tradeoffs.

    In this talk, Dan and I are going to talk about these tradeoffs by looking at three approaches to ORM with Ruby.
  • You’re probably familiar with this already, so I won’t show much code here or talk about how to use AR. Instead, let’s talk for a few minutes at a more theoretical level.
  • In this pattern, an object wraps each DB row. This single object handles both domain logic and database access. What's unique about this?
  • Other approaches might not treat each row as an object, or might combine multiple rows into a single object.
  • Others might separate these, filtering the data through a logic layer, instead of exposing both side-by-side.

  • class User < ActiveRecord::Base

    That does a _lot_. And from looking at this, you have no idea exactly what it did. You have to check the db schema in order to figure that out.

    The good news is that convention dominates. Once you know the conventions, you generally aren't surprised.
  • This is true, by default. N+1, loads all columns, etc.

    It would be really nice if it could do these things.

    But at the same time, it provides facilities for these sorts of optimizations.

  • This is part of the reason that alternative ORMs got started.

    The thing is, it isn't true any more. At least not entirely.

  • This guy, Josh Peek, made Rails 2.2 thread safe.
  • And this guy, who you may recognize, added the current connection pooling.
  • The fact is, as a AR developer, you can pretty much forget how to write a join.

    This isn't really a limitation of AR - some could say that it&#x2019;s a feature. But at the same time, you really do need to know SQL if you&#x2019;re going to use a relational database.

    That said, my SQL skills have atrophied as a Rails developer. On our newest project, Luke and I have had to do quite a bit of custom SQL, and we've tried to make our DB layer a bit smarter and more robust. Which leads to the next criticism...

  • Rails makes polymorphic associations easy and multi-table inheritance hard.

    But polymorphic associations: bad idea. Cuts out a join table, but hurts referential integrity. But because it&#x2019;s easy, you see a lot of it.

    Is this a valid criticism? It usually isn&#x2019;t that hard to fight against AR&#x2019;s conventions, and most of the time, you don&#x2019;t want to.
  • This is bad. Basically, foreign keys require a plugin. Redhill. This plugin works, but isn't all that actively maintained, and some things (constraints) aren't even supported by that.

    You can always run a bare connection.execute() statement, but this won't get dumped into your schema.rb file, which is bad.

    According to DHH et al, you don't need DB constraints, and you want a dumb DB.

  • 4. Access your database directly.

  • Company 1 may not exist.


  • I.e. you make a mistake
  • I.e. you make a mistake.

    This probably isn&#x2019;t a problem for you, but it might be for some of the other people you work with.
  • Sequel is a thread-safe DB library with a lightweight ORM

  • Follows the ActiveRecord pattern
  • So you don&#x2019;t have to write much real SQL
  • So you don&#x2019;t have to write much real SQL
  • The Sequel ORM is very similar to AR, at least on the surface.

    Does many of the things that Rails does, at least the basics.

  • Also has similar support for sharding

  • Rails and alternative ORMs

    1. 1. Rails and Alternative ORMs Dan Weinand Jonathan Dahl
    2. 2. Why?
    3. 3. DB vs. OO declarative vs. imperative
    4. 4. DB vs. OO char/text vs. string
    5. 5. DB vs. OO schema vs. _______
    6. 6. DB vs. OO joins vs. pointers
    7. 7. DB vs. OO public vs. encapsulated
    8. 8. DB vs. OO constraints vs. validation
    9. 9. DB vs. OO _____ vs. inheritance
    10. 10. DB vs. OO DBA vs. programmer
    11. 11. DB vs. OO structure vs. behavior
    12. 12. http://www.engrish.com//wp-content/uploads/2008/08/hand-grenade.jpg
    13. 13. 1. ActiveRecord
    14. 14. An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data. Martin Fowler, PoEAA, 160.
    15. 15. One object per row.
    16. 16. Data access and domain logic are done together.
    17. 17. 6 Criticisms of ActiveRecord
    18. 18. 1. Too much magic. http://cgi.ebay.com/MEDIEVAL-MAGE-KING-BLACK-TUNIC-COSTUME-SCA-LARP-_W0QQitemZ250373576829QQcmdZViewItemQQimsxZ20090215?IMSfp=TL090215143008r8810#ebayphotohosting
    19. 19. class User < ActiveRecord::Base end
    20. 20. 2. Not performant. http://www.flickr.com/photos/danprates/1418154518/
    21. 21. 3. Not thread safe. No connection pooling. http://www.flickr.com/photos/streetmuseo/57990915/
    22. 22. 4. Hides SQL from you. http://www.momentaryfascinations.com/entertainment/the.lost.monty.python.cartoon/still.5.jpg
    23. 23. 5. Hard to fight against. http://www.mmonotebook.com/wp-content/uploads/2008/04/larp.jpg
    24. 24. 6. Encourages stupid databases.
    25. 25. 9 ways to bypass application-level constraints
    26. 26. 1. Fixtures
    27. 27. 2. Klass.delete(1)
    28. 28. 3. record.save(false)
    29. 29. 4.
    30. 30. 5. Share DB with a second app
    31. 31. 6. User.create(:company_id => 1)
    32. 32. class User < ActiveRecord::Base 7. has_many :posts end
    33. 33. 8. ActiveRecord::Base.connection.execute()
    34. 34. 9. Errors in your app logic
    35. 35. 2. Sequel
    36. 36. An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data. Martin Fowler, PoEAA, 160.
    37. 37. Ruby DSL for SQL posts = DB[:posts] posts.filter(:category => /ruby/i, :author => [:jon, :dan]) posts.reverse_order(:created_at, :updated_at) posts.select(:title, :author) posts.limit(10)
    38. 38. Ruby-like DSL for SQL posts.filter(:category => :ruby).order(:created_at).select(:title, :author)
    39. 39. ORM class Post < Sequel::Model many_to_many :tags many_to_one :author validates_presence_of :title end post = Post[123] post.title # quot;rails ormsquot; post.title = quot;Rails ORMsquot; post.save
    40. 40. 3 interesting things sequel postgres://localhost:5432/myapp_development
    41. 41. 3 interesting things require 'memcache' CACHE = MemCache.new 'localhost:11211', :namespace => 'blog' class Author < Sequel::Model set_cache CACHE, :ttl => 3600 end Author[333] # database hit Author[333] # cache hit
    42. 42. 3 interesting things DB = Sequel.sqlite('app_test.db', :servers=>{:read_only=>{:host=>'slave_server'}})
    43. 43. 3. Datamapper
    44. 44. A layer of Mappers (473) that moves data between objects and a database while keeping them independent of each other and the mapper itself. Martin Fowler, PoEAA, 165.
    45. 45. Multiple Databases • SQL-based • In-memory • Document-based • Search engines
    46. 46. Explicit property mapping class Message include DataMapper::Resource property :name, String property :body, Text property :created_at, DateTime validates_presence_of :name end
    47. 47. Get only the data you need
    48. 48. Minimize the number of queries
    49. 49. Save only the data that has changed
    50. 50. Identity Map repository do @parent.children.each do |child| puts @parent.object_id = child.parent.object_id end end
    51. 51. Ruby Query Syntax Zoo.first(:name.eql => 'Galveston') Person.all(:age.gt => 30) Person.all(:age.gte => 30) Person.all(:name.not => 'bob') Person.all(:name.like => 'S%', :id => [1,2,3,4,5]) Person.all(:name.not => ['bob','rick','steve']) Person.all(:order => [:age.desc])
    52. 52. Chainable finders class Zoo def self.open all(:open => true) end def self.big all(:animal_count.gte => 1000) end end big_open_zoos = Zoo.big.open
    53. 53. Associations class Article include DataMapper::Resource property :id, Serial property :title, String property :content, Text belongs_to :author end class Author include DataMapper::Resource property :id, Serial property :name, String has n, :articles end Article.all('author.name' => 'Michael')
    54. 54. Implicit and explicit migrations
    55. 55. Only basic functionality in core
    56. 56. Gems for everything else
    57. 57. Is it ready for primetime?
    58. 58. Roadmap to 1.0
    59. 59. Rails integration still lacking
    60. 60. Not many production deployments
    61. 61. Documentation sucks
    62. 62. Some plugins still not ported
    63. 63. Thanks! Dan Weinand Jon Dahl