【问题标题】:Dynamically create Ruby class with ActiveRecord connection使用 ActiveRecord 连接动态创建 Ruby 类
【发布时间】:2017-08-07 01:50:12
【问题描述】:

我正在尝试动态创建一个类并将几个数据库连接之一分配给每个类。

我正在使用随时间变化的两个或三个数据库之间的任何地方,因此,我不愿将每个连接字符串存储在一个单独的类中并从它继承而不是 ActiveRecord::Base。

以下会引发错误“RuntimeError: Anonymous class is not allowed.”,但我不确定如何解决它或是否有更好的替代方案。

  class ClassFactory
    def self.create_class(new_class, table, db_connection)

      c = Class.new(ActiveRecord::Base) do
        db = db_connection
        self.table_name = table
        establish_connection(:adapter => db.database_type, :host => db.host, :database => db.database, :username => db.username, :password => db.password).connection
      end

      Module.const_set new_class, c
    end
  end

【问题讨论】:

    标签: ruby-on-rails ruby class activerecord metaprogramming


    【解决方案1】:

    根据ActiveRecord::ConnectionHandling#establish_connection's source,您无法从name 不返回真实值的类建立连接。

    现在,您正在使用const_set 将类分配给一个常量,这将为它命名。但是您需要在调用establish_connection 之前这样做:

    class ClassFactory
      def self.create_class(new_class, table, db_connection)
        c = Class.new(ActiveRecord::Base) do
          db = db_connection
          self.table_name = table
        end
    
        Module.const_set new_class, c
        c.establish_connection(:adapter => db.database_type, :host => db.host, :database => db.database, :username => db.username, :password => db.password).connection
      end
    end
    

    另外,你真的想要Module.const_set(...)吗?这将产生一个名为Module::Foo 的类。可能你只想要Object.const_set(...)(它只是给Foo)?甚至const_set(...),所以你得到ClassFactory::Foo

    【讨论】:

    • 谢谢,这很有帮助。你说得对,我不想那样。
    【解决方案2】:

    您可以为模型动态设置establish_connection

    数据库.yml

    development:
      adapter: mysql
      username: root
      password: 
      database: example_development
    
    oracle_development:
      adapter: oracle
      username: root
      password: 
      database: example_oracle_development
    

    并且在任何代码位置,您都可以更改模型的数据库连接:

    User.establish_connection "oracle_#{RAILS_ENV}".to_sym
    

    您还可以动态创建模型类:

    class ClassFactory
      def self.create_class(new_class, table, connection_name)
    
        Object.const_set(new_class, Class.new(ActiveRecord::Base) {})
        new_class.constantize.table_name = table
        new_class.constantize.establish_connection(connection_name)
    
      end
    end
    
    ClassFactory.create_class('NewUser', 'users', :development)
    

    之后,NewUser 类就可以使用了。

    此版本适用于 Rails 5.0 和 3.2。

    【讨论】:

    • 根据我对源代码的阅读,这应该行不通; ActiveRecord::ConnectionHandling#establish_connection 的第一行是raise "Anonymous class is not allowed." unless name,然后再看一下您传入的参数。我是不是误会了什么?
    • 看起来代码只能在 Rails 3.2 或更早版本中工作。 establish connection source。给我一秒钟,我会尝试让它在新的 Rails 中工作。
    • 有趣,我在看ActiveRecord::ConnectionHandling#establish_connection,而不是ActiveRecord::ConnectionPool::ConnectionHandler#establish_connection。必须喜欢令人困惑的相似名称。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-10
    • 2023-03-14
    • 2019-06-17
    相关资源
    最近更新 更多