-->

Rails 3 using MongoDB via mongoid adapter - is the

2019-05-10 08:28发布

问题:

Probably a confusing title, but not sure how else to put it. Example should make it clearer. I have many different models that share many of the same attributes. So in each model I have to specify those same attributes and THEN the attributes that are specific to that particular model.

Is there any way I can create some class that lists these basic attributes and then inherit from that class without using Single-Table Inheritance? Because if I put all the shared attributes and Mongoid includes into a single model and inherit from that base model in the other models, then STI is enforced and all my models are stored in a single mongodb collection, differentiated by a "_type" field.

This is what I have:

class Model_1
  include Mongoid::Document

  field :uuid, :type => String
  field :process_date, :type => String
  ...
end

class Model_2
  include Mongoid::Document

  field :uuid, :type => String
  field :process_date, :type => String
  ...
end

But this is the functionality I'm after:

class Base_model
  field :uuid, :type => String
  field :process_date, :type => String
end

class Model_1 < Base_model
  # To ensure STI is not enforced
  include Mongoid::Document

  # Attribute list inherited from Base_model
end

The issue is that if you don't have the "include Mongoid::Document" in the Base_model, then that base model doesn't know about the "field ..." functionality. But if you do put the mongoid include in the base model and inherit from it, STI is enforced.

I can't do STI for this particular situation but it's a coding nightmare to have multiple models, all with the same attributes list specified over and over (there are a growing number of models and each share about 15-20 attributes, so anytime I have to change a model name it's a lot of effort to change it everywhere...).

回答1:

You can define the common attributes in a module and include that.

require 'mongoid'

module DefaultAttrs

  def self.included(klass)
    klass.instance_eval do
      field :uuid, :type => String
    end
  end

end

class Foo
  include Mongoid::Document
  include DefaultAttrs

  field :a, :type => String
end

class Bar
  include Mongoid::Document
  include DefaultAttrs

  field :b, :type => String
end


回答2:

I had the exact same question and wanted to go for the mixin approach initially. However, after talking to some experts it turns out that using mongoids single table inheritance (one collection for all child elements) may be the way to go, depending on your use case. Please see my post here: single collection vs. separate collections for inherited objects



回答3:

You can bundle them into a new module, i.e.

module Mongoid
  module Sunshine
    extend ActiveSupport::Concern

    included do
      include Mongoid::Document
      include Mongoid::Timestamps
      include Mongoid::TouchParentsRecursively
      include Mongoid::Paranoia
      include Mongoid::UUIDGenerator
    end
  end
end


class School
  include Mongoid::Sunshine
end