gpt4 book ai didi

ruby-on-rails - 在 Rails 应用程序中的查询运行时更改表名

转载 作者:太空宇宙 更新时间:2023-11-03 17:29:07 24 4
gpt4 key购买 nike

我在 Apache + mod_passenger 上有一个胖 Multi-Tenancy Rails 应用程序,它从 PostgreSQL 表输出产品价格,如下所示:

Table "public.products"
Column | Type
id | bigint
name | character varying(100)
price | numeric(8,2)

然后在 products.rb 里面我有...

class Product < PostgresDatabase
self.table_name = "products"

# ... yadda yadda

end

我想要的是以一种非常具体的方式对“产品”表进行分区,以便我最终为每个租户得到类似 products_TENANT-ID 的东西(基本上是主产品表的 View ,但那是另一回事)并且能够像这样查询:

Products.for_tenant(TENANT-ID).where(:name => "My product")......

我想我可以创建一个方法:

class Product < PostgresDatabase
self.table_name = "products"

# ... yadda yadda
def for_tenant(tid)
self.table_name = "products_" + tid.to_s
self
end
end

但是考虑到有大量流量(每秒数千个请求),这会对应用程序产生什么样的影响?有什么我想念的吗?我应该尝试不同的策略吗?

非常感谢您的任何反馈/想法!

最佳答案

方法

def self.for_tenant(tid)
self.table_name = "products_" + tid.to_s
self
end

是有道理的,然而,它有一个副作用:它改变了 Product 的表名。类(class)。当稍后在同一个请求中使用这个类时,例如,以这种方式:

Product.where(name: "My other product") ...

表名不会是products如您所料;它将保持与 for_tenant 更改的相同以前的方法。

为避免这种歧义并保持代码整洁,您可以使用另一种策略:

1) 定义一个模块,其中包含租户分区的所有工作逻辑:

# app/models/concerns/partitionable.rb

module Partitionable
def self.included(base)
base.class_eval do
def self.tenant_model(tid)
partition_suffix = "_#{tid}"

table = "#{table_name}#{partition_suffix}"

exists = connection.select_one("SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = '#{table}')")
unless exists['exists'] == 't' || exists['exists'] == true # different versions of pg gem give different answers
return self # returning original model class
end

class_name = "#{name}#{partition_suffix}"

model_class = Class.new(self)

model_class.define_singleton_method(:table_name) do
table
end

model_class.define_singleton_method(:name) do
class_name
end

model_class
end
end
end
end

2) 在您的模型类中包含此模块:

class Product < PostgresDatabase
include Partitionable

...
end

3) 按照您的预期使用它:

Product.tenant_model(TENANT_ID).where(name: "My product")...

那里发生了什么:

方法tenant_model(TENANT_ID)为 ID 为 TENANT_ID 的租户创建另一个模型类.此类的名称为 Product_<TENANT_ID> , 适用于表 products_<TENANT_ID>并继承Product的所有方法类(class)。所以它可以像普通模型一样使用。和类Product本身保持不变:它的 table_name还是products .

关于ruby-on-rails - 在 Rails 应用程序中的查询运行时更改表名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52537951/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com