【问题标题】:How to specify polymorphic association with custom primary keys in Rails如何在 Rails 中指定与自定义主键的多态关联
【发布时间】:2013-01-08 00:11:09
【问题描述】:

我有几个 ActiveRecord 类使用paper_trail 进行版本跟踪。 AR 类具有基于其表名的自定义主键(例如 Item.ItemID 而不是 Item.id),以遵守业务 DB 约定。

paper_trail 指定每个跟踪类的多态关系,因此:

class TrackedExample < ActiveRecord::Base
    set_table_name 'TrackedExample'
    set_primary_key 'TrackedExampleID'

    # simplified from https://github.com/airblade/paper_trail/blob/master/lib/paper_trail/has_paper_trail.rb
    has_many :versions
        :class_name => 'Version'
        :as         => :item,
end

class AnotherTrackedExample
    set_table_name 'AnotherTrackedExample'
    set_primary_key 'AnotherTrackedExampleID'

    has_many :versions
        :class_name => 'Version'
        :as         => :item,
end

# from https://github.com/airblade/paper_trail/blob/master/lib/paper_trail/version.rb
class Version
    belongs_to :item, :polymorphic => true
    ...
 end

如果我没有使用自定义主键,版本对象可以使用Version#item 引用被跟踪的对象(即它是版本的对象)。当我尝试它时,我得到一个错误:

# This should give back `my_tracked_example`
my_tracked_example.version.first.item

=> TinyTds::Error: Invalid column name 'id'.: EXEC sp_executesql N'SELECT TOP (1) [TrackedExample].* FROM [TrackedExample] WHERE [TrackedExample].[id] = 1 ORDER BY TrackedExample.TrackedExampleID ASC'

有没有办法让 Version#item 执行正确的查询?我希望是这样的:

EXEC sp_executesql N'SELECT TOP (1) [TrackedExample].* FROM [TrackedExample] WHERE [TrackedExample].[TrackedExampleID] = 1 ORDER BY TrackedExample.TrackedExampleID ASC'

我正在通过 TinyTDS 和 activerecord-sqlserver-adapter 使用 Rails 3.1.0、paper_trail 2.6.4 和 MS SQL Server。

编辑:我通过添加引用主键值的计算列 TrackedExample.idAnotherTrackedExample.id 解决了这个问题。这不是一个合适的解决方案(Rails 仍在进行错误的查询),但它可能对其他匆忙的人有用。

MS SQL:

ALTER TABLE TrackedExample
    ADD COLUMN id AS TrackedExampleID

【问题讨论】:

    标签: ruby-on-rails polymorphic-associations


    【解决方案1】:

    而不是在迁移文件中指定t.references :itempolymorphic: true。 您只需指定item_iditem_type,如下所示:

    t.string :item_id
    
    t.string :item_type
    

    Rails 会自动为item_id 选择正确的primary_key 和正确的类型。

    【讨论】:

      【解决方案2】:

      我没有尝试过,但这可能有效

      class Version
        belongs_to :item, :polymorphic => true, :primary_key => 'TrackedExampleID'
        ...
      end
      

      【讨论】:

      • 如果所有跟踪的类都具有相同的主键,那将可以正常工作。我的问题是它们都是不同的,我不知道如何告诉 Version 类(如果可能的话)。编辑示例以使情况更清楚。
      • 查看 rails 源代码我认为您的原始代码应该按原样工作。如果您不设置主键,ActiveRecord 似乎正在询问多态父级的主键。我不希望有什么不同,但请尝试使用 self.primary_key= 而不是 set_primary_key?
      • 使用self.primary_key= 没有任何区别,正如预期的那样。不过谢谢你的建议。
      • 我已经验证您的原始代码在带有 MySQL 的 Rails 3.2 中可以正常工作。不幸的是,我没有 MS SQL 或 Rails 3.1 可供测试。
      【解决方案3】:

      在搜索 PaperTrail 文档后,您似乎无法覆盖 item_id 引用的列(即 Item 表的主键),所以我认为您有两个主要选择:

      1.创建一个id 列,其中没有类的名称。所以,id 而不是 TrackedExampleID

      你说你已经做了这个作为一个快速修复。

      2。分叉和修补 PaperTrail 以允许您在查询 item_id 时传递要使用的列。

      这可以是使用set_primary_key 'TrackedExampleID' 设置的值,也可以是设置为has_paper_trail primary_key: 'TrakedExampleID' 之类的值。

      让我们知道您的最终结果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-18
        相关资源
        最近更新 更多