学习ActiveRecord中的动态模型与PostgreSQL

62 阅读1分钟

提示:ActiveRecord中的动态模型与PostgreSQL

我最近不得不面对的一个问题是根据某种模式动态地访问表。想想有以下格式的表。table_1,table_2...table_n ,或者任何其他的格式,说实话,只要想一想众所周知的格式

这个问题的另一个有趣的地方还在于,我们被要求同时使用PostgreSQL和Schemas来以某种方式更好地组织数据。那么,如何在PostgreSQL中用ActiveRecord动态地创建也刚好使用不同模式的类模型呢?

这个解决方案非常简单,而且非常直接。

require 'active_record'

class ModelFactory < ActiveRecord::Base
  self.abstract_class = true

  class << self
    def build_model(params)
      schema = params[:schema]
      table = params[:table]
      full_name = "#{schema}.#{table}"

      create_database_objects(schema, table, full_name)

      model = Class.new(ModelFactory) do
        self.table_name = full_name
      end

      model
    end

    private
    def create_database_objects(schema, table, full_name)
      connection = ModelFactory.connection

      # Create Schema 
      unless connection.schema_exists?(schema)
        begin
          connection.create_schema(schema)
        rescue PG::DuplicateSchema
        end
      end

      # Create Table
      new_table = false
      unless connection.table_exists?(full_name)
        new_table = true
        begin
          connection.create_table(model.table_name) do |table|
            table.column :name, :string, limit: 50, null: false
            table.column :address, :string, limit: 300, null: false
          end
        rescue PG::DuplicateTable
        end
      end

      # What's next? Maybe adding indexes, who knows, sky is the limit
    end
  end

end

有了它,你可以轻松地做一些事情。

model = ModelFactory.build_model({schema: 'important_stuff', table: 'some_table'})
model.new(name: 'Mario', address: '742 Evergreen Terrace').save!

上面的代码的解释很简单。

  1. 你需要一个抽象类,因为你的新动态类必须要有子类才能引用真正的表。
  2. 方法ModelFactory.build_model ,用于创建新的模型。
  3. 除了创建模型,实际的模式和表也被创建,以防它们不存在,创建被包裹在一个begin/rescue 部分,以防多个ModelFactory 实例同时收到创建相同模式+表的消息。

清晰而特别简单的解决方案。