0

I'm trying to create a dynamic application to create any kind of data needed through metaprogramming the MVC i tried this for models:

class DynamicRecord

    attr_accessor :name, :attributes

    def initialize(name, attributes = [])
        raise "Error: Constant #{name} already in namespace" if name.in? Object.constants
        a_new_class = Class.new(Object) do |clazz|
            include Mongoid::Document
            attributes.map do |attribute|
                field attribute[:name], type: attribute[:type]
            end
        end
        Object.const_set(name, a_new_class) 
    end
end

DynamicRecord.new('Person', [{name: :name, type: String}, {name: :email, type: String}])

person = Person.new(name: "Foo", email: "[email protected]")
person.save

Then I get this error:

Mongo::Error::OperationFailure: Invalid ns [mongodb_divcad_development.] (16257)
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/operation/result.rb:256:in `validate!'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/operation/write/insert.rb:60:in `block in execute_message'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/server/connection_pool.rb:107:in `with_connection'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/server.rb:242:in `with_connection'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/operation/write/insert.rb:59:in `execute_message'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/operation/write/write_command_enabled.rb:39:in `execute'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/collection.rb:365:in `block in insert_one'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/retryable.rb:112:in `write_with_retry'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongo-2.4.1/lib/mongo/collection.rb:356:in `insert_one'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/query_cache.rb:182:in `insert_one_with_clear_cache'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/creatable.rb:79:in `insert_as_root'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/creatable.rb:27:in `block in insert'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/creatable.rb:118:in `block (2 levels) in prepare_insert'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/activesupport-4.0.2/lib/active_support/callbacks.rb:373:in `_run__4510143668266298615__create__callbacks'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/activesupport-4.0.2/lib/active_support/callbacks.rb:80:in `run_callbacks'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/interceptable.rb:138:in `run_callbacks'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/creatable.rb:117:in `block in prepare_insert'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/activesupport-4.0.2/lib/active_support/callbacks.rb:373:in `_run__4510143668266298615__save__callbacks'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/activesupport-4.0.2/lib/active_support/callbacks.rb:80:in `run_callbacks'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/interceptable.rb:138:in `run_callbacks'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/creatable.rb:116:in `prepare_insert'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/creatable.rb:23:in `insert'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/mongoid-5.2.0/lib/mongoid/persistable/savable.rb:23:in `save'
    from (irb):70
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/railties-4.0.2/lib/rails/commands/console.rb:90:in `start'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/railties-4.0.2/lib/rails/commands/console.rb:9:in `start'
    from /home/cassiano/.rvm/gems/ruby-2.3.3/gems/railties-4.0.2/lib/rails/commands.rb:62:in `<top (required)>'
    from bin/rails:4:in `require'
    from bin/rails:4:in `<main>'

This can be done? There is a better approach without falling into a Entity-attribute-value model?

2 Answers 2

4

Mongoid doesn't know about namespace when you try to use dynamic model. In order to fix it you should set namespace with store_in

Example:

class DynamicCollection
  def self.create(collection, fields)
    klass = Class.new do
      include Mongoid::Document
      store_in collection: collection.downcase

      fields.each do |item|
        field item[:name], type: item[:type]
      end
    end

    Object.const_set(collection, klass) 
  end
end

fields = [
  {name: 'name', type: String},
  {name: 'email', type: String}
]

DynamicCollection.create('Demo', fields)

Demo.create!(name: 'SomeValue', email: 'SomeValue')
Sign up to request clarification or add additional context in comments.

Comments

0

I didn't try this locally, and this could be a dumb answer...but I would change

attributes.map to attributes.each seems like map would return an array and would cause an error.

Also... https://github.com/mongodb/mongoid/blob/master/lib/mongoid/fields.rb#L335

Looking at the source for mongoid. There is a method called add_field that you maybe able to utilize.

1 Comment

I tried this: a_new_class = Class.new(Object) do include Mongoid::Document include Mongoid::Fields attributes.each do |attribute| field attribute[:name], type: attribute[:type] add_field attribute[:name] end end Same error... =/ The .map work as well

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.