【问题标题】:How to dynamic create models with RoR and mongodb?如何使用 RoR 和 mongodb 动态创建模型?
【发布时间】:2017-03-13 17:41:36
【问题描述】:

我正在尝试创建一个动态应用程序,以通过对 MVC 进行元编程来创建所需的任何类型的数据,我尝试将其用于模型:

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: "Foo@foo.com")
person.save

然后我得到这个错误:

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>'

这可以吗?有没有更好的方法而不陷入实体-属性-价值模型?

【问题讨论】:

    标签: ruby-on-rails mongodb mongoid metaprogramming


    【解决方案1】:

    当您尝试使用动态模型时,Mongoid 不知道命名空间。为了修复它,您应该使用 store_in

    设置命名空间

    例子:

    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')
    

    【讨论】:

      【解决方案2】:

      我没有在本地尝试过,这可能是一个愚蠢的答案......但我会改变

      attributes.map 到 attributes.each 似乎 map 会返回一个数组并导致错误。

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

      寻找mongoid的来源。有一个名为 add_field 的方法,您也许可以使用它。

      【讨论】:

      • 我试过这个: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 同样的错误... =/ .map 也能正常工作
      猜你喜欢
      • 1970-01-01
      • 2015-06-22
      • 1970-01-01
      • 2023-04-10
      • 1970-01-01
      • 2023-01-31
      • 2020-09-22
      • 2022-10-06
      • 1970-01-01
      相关资源
      最近更新 更多