Search code examples
sqlruby-on-railsmongodbruby-on-rails-3.1nosql

Rails: mixing NOSQL & SQL Databases


I'm looking for the better way (aka architecture) to have different kind of DBs ( MySQL + MongoDB ) backending the same Rails app.

I was speculating on a main Rails 3.1 app, mounting Rails 3.1 engines linking each a different kind of DB ...

... or having a main Rails 3.0.x app routing a sinatra endpoint for each MySQL/MongoDB istance ...

Do you think it's possible ..., any idea or suggestions ?

I notice some other similar questions here, but I think that "mounting apps" is moving fast in Rails 3.1 / Rack / Sinatra and we all need to adjust our paradigms.

Thanks in advance Luca G. Soave


Solution

  • There's no need to completely over-complicate things by running two apps just to have two types of database. It sounds like you need DataMapper. It'll do exactly what you need out of the box. Get the dm-rails gem to integrate it with Rails.

    In DataMapper, unlike ActiveRecord, you have to provide all the details about your underlying data store: what fields it has, how they map the attributes in your models, what the table names are (if in a database), what backend it uses etc etc.

    Read the documentation... there's a bucket-load of code to give you an idea.

    Each model is just a plain old Ruby object. The class definition just mixes in DataMapper::Resource, which gives you access to all of the DataMapper functionality:

    class User
      include DataMapper::Resource
    
      property :id,            Serial
      property :username,      String
      property :password_hash, String
      property :created_at,    DateTime
    end
    

    You have a lot of control however. For example, I can specify that this model is not store in my default data store (repository) and that it's stored in one of the other configured data stores (which can be a NoSQL store, if you like).

    class User
      include DataMapper::Resource
    
      storage_names[:some_other_repo] = 'whatever'
    
      # ... SNIP ...
    end
    

    Mostly DM behaves like ActiveRecord on steroids. You get all the basics, like finding records (except you never have to use the original field names if your model abstracts them away):

    new_users = User.all(:created_at.gte => 1.week.ago)
    

    You get validations, you get observers, you get aggregate handling... then get a bunch of other stuff, like strategic eager-loading (solves the n+1 query problem), lazy loading of large text/blob fields, multiple repository support. The query logic is much nicer than AR, in my opinion. Just have a read of the docs. They're human-friendly. Not just an API reference.

    What's the downside? Well, many gems don't take into account that you might not be using ActiveRecord, so there's a bit more searching to do when you need a gem for something. This will get better over time though, since before Rails 3.x seamlessly integrating DM with Rails wasn't so easy.