提示: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!
上面的代码的解释很简单。
- 你需要一个抽象类,因为你的新动态类必须要有子类才能引用真正的表。
- 方法
ModelFactory.build_model,用于创建新的模型。 - 除了创建模型,实际的模式和表也被创建,以防它们不存在,创建被包裹在一个
begin/rescue部分,以防多个ModelFactory实例同时收到创建相同模式+表的消息。
清晰而特别简单的解决方案。