rubyactiverecordmongoidmongoid3

Referencing the same model 3 times from another model in Mongoid


I have two models as below:

class Tag
  include Mongoid::Document
  include Mongoid::Timestamps
  belongs_to :group
end

class Group
  include Mongoid::Document
  include Mongoid::Timestamps

  has_one :user_tag, :class_name => 'Tag', :foreign_key => "user_tag_id", :inverse_of => nil
  has_one :tag_tag, :class_name => 'Tag', :foreign_key => "tag_tag_id", :inverse_of => nil
  has_one :group_tag, :class_name => 'Tag', :foreign_key => "group_tag_id", :inverse_of => nil
end

But this and other attempts haven't seemed to yield the desired result of having 3 different types of Group separately referencable. Any help would be very much appreciated!


Solution

  • I think that the following does what you want, albeit with three additional trivial models/subclasses. My attempts to do this with just the Tag class and no subclasses ran into collisions and other issues with the inverse relationship, even when loosening restrictions with polymorphism. Maybe the three additional trivial subclasses are OK for your purposes? Note that the tag data is still stored in the one 'tag' collection as specified by the 'store_in' method.

    app/models/group.rb

    class Group
      include Mongoid::Document
      include Mongoid::Timestamps
      field :name, type: String
    
      has_one :user_tag
      has_one :tag_tag
      has_one :group_tag
    end
    

    app/models/tag.rb

    class Tag
      include Mongoid::Document
      include Mongoid::Timestamps
      field :text, type: String
    
      belongs_to :group
      store_in collection: 'tag'
    end
    

    app/models/group_tag.rb

    class GroupTag < Tag
    end
    

    app/models/tag_tag.r

    class TagTag < Tag
    end
    

    app/models/user_tag.rb

    class UserTag < Tag
    end
    

    test/unit/group_test.rb

    require 'test_helper'
    require 'pp'
    
    class GroupTest < ActiveSupport::TestCase
      def setup
        Mongoid.default_session.drop
      end
      test '0. mongoid version' do
        puts "\nMongoid::VERSION:#{Mongoid::VERSION}\nMoped::VERSION:#{Moped::VERSION}"
      end
      test 'multiple tag references' do
        group = Group.create(name: 'my group')
        group.user_tag = UserTag.create(text: 'user tag')
        group.tag_tag = TagTag.create(text: 'tag tag')
        group.group_tag = GroupTag.create(text: 'group tag')
        assert_equal(1, Group.count)
        assert_equal(3, Tag.count)
        puts
        puts "Group:"
        pp Group.all.to_a
        puts "Tag:"
        pp Tag.all.to_a
        puts "collections: #{Mongoid.default_session.collection_names.inspect}"
      end
    end
    

    rake test

    Run options:

    Running tests:

    [1/2] GroupTest#test_0._mongoid_version
    Mongoid::VERSION:3.1.6
    Moped::VERSION:1.5.2
    [2/2] GroupTest#test_multiple_tag_references
    Group:
    [#<Group _id: 53f242b27f11ba5f31000001, created_at: 2014-08-18 18:15:14 UTC, updated_at: 2014-08-18 18:15:14 UTC, name: "my group">]
    Tag:
    [#<UserTag _id: 53f242b27f11ba5f31000002, created_at: 2014-08-18 18:15:14 UTC, updated_at: 2014-08-18 18:15:14 UTC, text: "user tag", group_id: "53f242b27f11ba5f31000001", _type: "UserTag">,
     #<TagTag _id: 53f242b27f11ba5f31000003, created_at: 2014-08-18 18:15:14 UTC, updated_at: 2014-08-18 18:15:14 UTC, text: "tag tag", group_id: "53f242b27f11ba5f31000001", _type: "TagTag">,
     #<GroupTag _id: 53f242b27f11ba5f31000004, created_at: 2014-08-18 18:15:14 UTC, updated_at: 2014-08-18 18:15:14 UTC, text: "group tag", group_id: "53f242b27f11ba5f31000001", _type: "GroupTag">]
    collections: ["groups", "tag"]
    Finished tests in 0.527855s, 3.7889 tests/s, 3.7889 assertions/s.
    2 tests, 2 assertions, 0 failures, 0 errors, 0 skips