ActiveMongoid facilitates usage of both ActiveRecord and Mongoid in a single rails application by providing an ActiveRecord-like interface for inter-ORM relations. It was written to replace select Mongoid models with ActiveRecord versions so it tries to adhere to the Mongoid API as closely as possible. To accomplish this compatibility, much of the logic and structure of this lib are either directly inspired by or straight up ripped off the Mongoid source.
Add this line to your application's Gemfile:
gem 'active_mongoid'
And then execute:
$ bundle
Or install it yourself as:
$ gem install active_mongoid
To add ActiveMongoid associations, simply add the ActiveMongoid::Associations module in both models and define the relations using the provided macros as you would with either ActiveRecord or Mongoid.
class Player < ActiveRecord::Base
include ActiveMongoid::Associations
belongs_to_document :team
has_one_document :stat, as: :target, autosave: true, dependent: :destroy
endclass Team
include Mongoid::Document
include ActiveMongoid::Associations
has_many_records :players, autosave: true, order: "name asc"
belongs_to_record :division
endThen you can interact with the models and relations just as you would with either ActiveRecord or Mongoid.
> team = Team.create
=> #<Team _id: 5453d55cb736b692ab000001, name: nil>
> player = team.players.build(name: "foo") # create will call save
=> #<Player id: nil, name: "foo", team_id: "5453d55cb736b692ab000001">
> team.player << Player.new(name: "foo1")
=> #<Player id: nil, name: "foo1", team_id: "5453d55cb736b692ab000001">
> team.players
=> [#<Player id: nil, name: "foo", team_id: "5453d55cb736b692ab000001">, #<Player id: nil, name: "foo1", team_id: "5453d55cb736b692ab000001">]
> player.team # binds the inverse
=> #<Team _id: 5453d55cb736b692ab000001, name: nil>
> team.save
=> true
> team.players
=> [#<Player id: 1, name: "foo", team_id: "5453d55cb736b692ab000001">, #<Player id: 2, name: "foo1", team_id: "5453d55cb736b692ab000001">]
> team.players.where(name: "foo") # returns relation so chaining is possible
=> [#<Player id: 1, name: "foo", team_id: "5453d55cb736b692ab000001">]
> team.players.where(name: "foo").where(id: 1)
=> [#<Player id: 1, name: "foo", team_id: "5453d55cb736b692ab000001">]
> player = Player.create(name: "baz")
=> #<Player id: 3, name: "baz", team_id: nil>
> team = player.build_team(name: "bar") # create_ will call save
=> #<Team _id: 5453d55cb736b692ab000002, name: "bar">
> team.players
=> [#<Player id: 3, name: "foo", team_id: "5453d55cb736b692ab000002">]
> player.team(true) # forces reload from database
=> nil has_many_records :playershas_many_documents :stats
Options:
orderNeeds to be formated according to ActiveRecord/Mongoid spec respectivelydependentAccepts::destroy, :deleteasPolymorphic relationforeign_keyForeign key for relationprimary_keyPrimary key for relationclass_nameAssociation class nameautosaveAccepts:true
has_one_record :playerbelongs_to_record :playerhas_one_record :statbelongs_to_record :stat
Options:
dependentAccepts::destroy, :deleteasPolymorphic relationforeign_keyForeign key for relationprimary_keyPrimary key for relationclass_nameAssociation class nameautosaveAccepts:true
team.playersReturns the relationteam.players(true)Forces reload from database and returns relationteam.players = [player]Assigns objects and calls dependent method on old valuesteam.players << playerAppends object and will save if base is persistedteam.players.build({player.attributes})Builds and binds object from attributes and binds relationteam.players.concat([player_1, player_2]Appends and binds array of objects. Will save if base is persistedteam.players.purgeRemoves all objects from relation and calls dependent method on objectsteam.players.delete(player)Removes object and calls dependent method on objectteam.players.delete_all(optional_criteria)Calls delete on all objectsteam.players.destroy_all(optional_criteria)Calls destroy on all objectsteam.players.eachIterates on on objectsteam.players.exists?Calls exists? on relationteam.players.find(params)Returns relation with criteria addedteam.players.nullifyClears loaded relationteam.players.blank?Returnstrueif emptyteam.players.create({player.attributes})Creates and binds from attributesteam.players.create!({player.attributes})Creates and binds form attributes and raises an exception if failsteam.players.find_or_create_by({player.attributes})Finds or creates a record from attributesteam.players.find_or_initialize_by({player.attributes})Finds or initializes a record from attributesteam.players.nil?returnsfalse
All other methods will defer to the ActiveRecord/Mongoid relation respectively.
player.statReturns the relationplayer.stat(true)Forces reload from database and returns relationplayer.stat = statAssigns object as relation. Will substitute old value and call dependent methodplayer.build_stat({})Builds and binds new object from attributesplayer.create_stat({})Creates and binds new object from attributes
All other methods called on relation will defer to the object.
The BsonId module faciliates the useage of BSON::ObjectId's on ActiveRecord objects. This module is especially helpful if you are migrating a model from a Mongoid object to an ActiveRecord object and want to carry over the old id.
class Division < ActiveRecord::Base
include ActiveMongoid::BsonId
bsonify_attr :_id, initialize: true
end> division._id
=> BSON::ObjectId('545289a7b736b6586a000001')
> division._id = BSON::ObjectId('545289a7b736b6586a000002')
=> BSON::ObjectId('545289a7b736b6586a000002')
> division._id = '545289a7b736b6586a000002'
=> BSON::ObjectId('545289a7b736b6586a000002')class Play < ActiveRecord::Base
include ActiveMongoid::Associations
include ActiveMongoid::Finders
include ActiveMongoid::BsonId
bsonify_attr :id, initialize: true, primary: true
end> play.id
=> '545289a7b736b6586a000001' # An issue with ActiveRecord does not allow casting this particular accessor
> play.id = BSON::ObjectId('545289a7b736b6586a000002')
=> BSON::ObjectId('545289a7b736b6586a000002')
> play._id = '545289a7b736b6586a000002'
=> BSON::ObjectId('545289a7b736b6586a000002')This module proxies the existing ActiveRecord find and where to perform casting of BSON::ObjectId's to string for queries. Additionally it'll default to the _id field if the object is a valid BSON::ObjectId and the _id field is present on the model.
class Division < ActiveRecord::Base
include ActiveMongoid::BsonId
include ActiveMongoid::Finders
bsonify_attr :_id, initialize: true
end> Division.find(1)
=> #<Division id: 1, _id: "545289a7b736b6586a000001", name: "new">
> Division.find(BSON::ObjectId('545289a7b736b6586a000001')
=> #<Division id: 1, _id: "545289a7b736b6586a000001", name: "new">
> Division.where(_id: BSON::ObjectId('545289a7b736b6586a000001')
=> [#<Division id: 1, _id: "545289a7b736b6586a000001", name: "new">]
> Division.where(id: BSON::ObjectId('545289a7b736b6586a000001')
=> [#<Division id: 1, _id: "545289a7b736b6586a000001", name: "new">]- Fork it ( https://github.com/[my-github-username]/active_mongoid/fork )
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request