Heading image for post: Bridging ActiveRecord and Mongoid

Ruby

Bridging ActiveRecord and Mongoid

Profile picture of Kevin Wang

When we pick technologies for clients, we use the right tool for the job and quite often roll custom solutions when necessary. In a recent project, we used both SQL ( ActiveRecord over Postgres) and NoSQL (Mongoid over MongoDB) solutions for the data persistence layer, modeled after the client's data characteristics, and it worked out quite well.

While working on this project, we found ourselves needing to traverse between the ActiveRecord side and the Mongoid side quite often as "1..many" relationships, so we wrote this piece of glue code to make that easier.

class ActiveRecord::Base
  def self.has_many_documents(association_name)
    class_eval %<
      def #{association_name}
        #{association_name.to_s.singularize.classify}.where(#{name.underscore}_id: id)
      end
    >
  end
end

module Mongoid::ActiveRecordBridge
  extend ActiveSupport::Concern

  included do
    def self.belongs_to_record(association_name, options={})
      association_class = options[:class_name] || association_name.to_s.singularize.classify
      class_eval %<
        field :#{association_name}_id, type: Integer
        index(#{association_name}_id: 1)

        def #{association_name}
          @#{association_name} ||= #{association_class}.where(id: #{association_name}_id).first if #{association_name}_id
        end

        def #{association_name}=(object)
          @#{association_name} = object
          self.#{association_name}_id = object.try :id
        end
      >
    end
end

Put this in an initializer, then in your ActiveRecord model, you can use "has_many_documents", and in your Mongoid document, you can use "belongs_to_record" and it just works! You could easily expand this to include "1..1" and "many..many" relationships.

class Property < ActiveRecord::Base
  ...  
  has_many_documents :default_rules
  ... 
end
class Rule
  include Mongoid::Document
  include Mongoid::ActiveRecordBridge
  ...  
  belongs_to_record :property
  belongs_to_record :updated_by, class_name: 'User'
  belongs_to_record :approved_by, class_name: 'User'
  ... 
end

More posts about Ruby Development

  • Adobe logo
  • Barnes and noble logo
  • Aetna logo
  • Vanderbilt university logo
  • Ericsson logo

We're proud to have launched hundreds of products for clients such as LensRentals.com, Engine Yard, Verisign, ParkWhiz, and Regions Bank, to name a few.

Let's talk about your project