0

2012 年 8 月 8 日更新

我已经缩小了问题的范围......

这条线有效

ActiveRecord::Base.connection.schema_search_path = ["11", "public"].join(",")

但这条线没有

ActiveRecord::Base.connection.schema_search_path = [workspace.id.to_s, "public"].join(",")

即使 workspace.id == 11

需要明确的是,“workspace.id”不会为循环的每次迭代更新。请注意,这只适用于 ActiveRecord::Base.connection.schema_search_path 命令

有任何想法吗?

原帖

为冗长的帖子道歉,但我真的被困住了。

背景

我正在使用 PostGreSQL 在 Rails 上开发一个多租户应用程序。租户通过 PG 模式分隔。我有一个由租户拥有的“工作区”的概念,并且在“公共”模式中有关联的记录。

每个单独的模式(工作区)都有一个“项目”表。

在每一页上,我想显示当前用户可以访问的工作区和项目的下拉列表。下拉列表的简化版本如下所示:

Workspace 1
- Project 1a
- Project 1b
Workspace 2
- Project 2a
- Project 2b
- Project 2c
...
...
Workspace 8
Project 8a

我在 lib/PgTools.rb 中有以下方法

def self.current_search_path
  ActiveRecord::Base.connection.select_value "SHOW search_path"
end

def self.set_search_path(name, include_public = true)
  path_parts = [name.to_s, ("public" if include_public)].compact
  ActiveRecord::Base.connection.schema_search_path = path_parts.join(",")
end

从 rails 控制台使用时,这些方法似乎可以正常工作。

问题

我在 application_helper.rb 中编写了一个辅助方法来创建下拉列表。我认为这是一个放置它的好地方,因为它必须显示在每一页上。在这个辅助方法中,我必须设置 PG 搜索路径(使用 PgTools.set_search_path),以便仅迭代来自适当工作区的项目。但是搜索路径似乎没有正确设置。

相关代码如下

current_user.workspaces.each do |workspace|


  html << '<li>' + workspace.name + "</li>"

  PgTools.set_search_path(workspace.id) unless Rails.env.test?
  html << '<li>Current search_path is ' + PgTools.current_search_path + '</li>'  <!-- DEBUG LINE
  Project.all.each do |project|

    html << "<li>"

    html << (link_to '- ' + project.name, edit_project_path(project.id))

    html << "</li>"
  end
end

当我查看输出时,我得到以下信息:

Workspace 1
  Setting search_path to 10
  Current search_path is 10, public
  - Project 1a
Workspace 2
  Setting search_path to 15
  Current search_path is 10, public
  - Project 1a
Workspace 3
  Setting search_path to 14
  Current search_path is 10, public
  - Project 1a

如您所见,搜索路径永远不会改变,我也不知道为什么。模块方法显然是可访问的,因为“current_search_path”方法工作正常。

当我跟踪 log/development.log 时,我得到以下输出:

Workspace Load (0.6ms)  SELECT "workspaces".* FROM "workspaces" INNER JOIN "workspace_memberships" ON "workspaces"."id" = wworkspace_memberships"."workspace_id" WHERE "workspace_memberships"."user_id" = 2 ORDER BY workspaces.name ASC
(0.1ms)  SHOW search_path
CACHE (0.0ms)  SELECT "projects".* FROM "projects"
CACHE (0.0ms)  SHOW search_path
CACHE (0.0ms)  SELECT "projects".* FROM "projects"
CACHE (0.0ms)  SHOW search_path
CACHE (0.0ms)  SELECT "projects".* FROM "projects"
CACHE (0.0ms)  SHOW search_path
CACHE (0.0ms)  SELECT "projects".* FROM "projects"
CACHE (0.0ms)  SHOW search_path
CACHE (0.0ms)  SELECT "projects".* FROM "projects"
CACHE (0.0ms)  SHOW search_path
CACHE (0.0ms)  SELECT "projects".* FROM "projects"
CACHE (0.0ms)  SHOW search_path
CACHE (0.0ms)  SELECT "projects".* FROM "projects"
CACHE (0.0ms)  SHOW search_path
CACHE (0.0ms)  SELECT "projects".* FROM "projects"
CACHE (0.0ms)  SHOW search_path

这可能表明存在缓存问题,但我真的在这里盲目飞行,并且不喜欢禁用缓存的想法,因为我不知道可能产生的其他影响。

任何想法都非常受欢迎。我也愿意接受有关我以完全错误的方式来实现最终结果的建议。

干杯,

凯尔。

4

2 回答 2

0

那很有意思。这是来源:

  def schema_search_path=(schema_csv)
    if schema_csv
      execute("SET search_path TO #{schema_csv}", 'SCHEMA')
      @schema_search_path = schema_csv
    end
  end

考虑到这两个陈述应该评估为完全相同的事情,这并不重要。您是否尝试在 id.to_s 周围加上括号?

于 2013-03-17T22:21:50.277 回答
0

我认为您的问题是您的架构名称以数字开头。我有一个类似的问题,我使用哈希作为模式名称。这是解决方案:

ActiveRecord::Base.connection.schema_search_path = %{"#{workspace.id}", public}

%{}只是定义字符串的另一种方式,以便您可以在字符串本身中使用实际的引号。

我希望这会有所帮助:D

于 2013-07-19T08:53:16.230 回答