【问题标题】:Rails/postgres, 'foreign keys' stored in array to create 1-many associationRails/postgres,“外键”存储在数组中以创建一对多关联
【发布时间】:2013-06-05 10:14:51
【问题描述】:

是否可以使用 postgres 数组在 rails (4) 中创建一对多/has_many 关联?我知道外键类型数组是不可能的。

示例:一个任务有多个受让人。传统上我会使用关联表来解决这个问题:tasks->assignees->users。使用数组,这不是必需的,因为可以存储多个“外键”。

然后可以使用以下查询来获取分配给我的所有任务:

select * from tasks where ? IN tasks.assignees

【问题讨论】:

  • 您将有兴趣了解正在处理基于数组的外键。他们可能会进入 PostgreSQL 9.4,但我认为他们不会进入 9.3。

标签: ruby-on-rails ruby postgresql


【解决方案1】:

您将无法让 Rails 识别此数组并将其用于关联。

但是,如果您想更快地搜索/过滤分配给用户的任务,您可以在任务对象中保留一组用户 ID。否则,您必须执行 JOIN 才能在标准关联表中查找分配给 Alice 的所有任务。

因此解决方案是保留关联表,同时将受理人用户 ID 复制到任务对象中,并使用该 ID 列表进行更快的搜索/过滤。

您需要挂钩到受让人对象的after_createafter_destroy 生命周期,并将新的受让人ID 插入任务记录数组。然后当从任务中删除受让人时,更新数组以删除 ID。

查看所有数组运算符的 Postgres 文档:

类似这样的:

class Task < ActiveRecord::Base
    has_many :assignees, :dependent => :destroy
end

class Asignee < ActiveRecord::Base

    belongs_to :task
    after_create :insert_task_assignee
    after_destroy :remove_task_assignee

    # assumes that there is a column called assignee_id
    # that contains the User ID of the assigned person

    private

    def insert_task_assignee
        # TODO: check for duplicates here - before we naively push it on?
        task.assignee_list = task.assignee_list.push(assignee_id)
        task.assignee_list.save
    end

    def remove_task_assignee
        id_list = task.assignee_list
        id_list.reject! { |candidate_id| candidate_id == assignee_id }
        task.assignee_list = id_list
        task.assignee_list.save
    end

end

# find all tasks that have been assigned Alice & Bob
# this will require the `postgres_ext` gem for Ruby / Postgres array searching
tasks = Task.where.contains(:assignee_list => [alice.id, bob.id]).all

【讨论】:

  • 但是如何让 Rails 通过数组知道关联,以便在包含模型时加载模型?
  • 您无法通过数组让 rails 知道关联。这将仅用作基本的“缓存”机制,并且可能是一种优化,因为可以直接查询任务,而不必执行JOIN
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-28
  • 1970-01-01
相关资源
最近更新 更多