【问题标题】:Rails 4 polymorphic has_many ignores table_nameRails 4 多态 has_many 忽略 table_name
【发布时间】:2016-04-25 22:49:09
【问题描述】:

短版:我正在构建一个新的 Rails 4 应用程序,它使用(只读)旧版 Rails 2 应用程序使用的数据库中的一些表,该应用程序仍在使用中。然而,旧应用程序模型/表的命名非常容易混淆(尤其是在新应用程序的上下文中),因此我想使用 self.table_name 为模型/表使用不同的名称。在我尝试添加多态关系之前,这一切都完美无缺。 Rails 忽略我定义的 table_name 并使用新模型名称对类型进行查询,这当然是不同的,所以它不起作用。有什么办法可以改变吗?

长版:这个方程中有三个模型,它们是:

class Exporter < MysqlBase
  has_many :lic_exporter_addresses, :as => :place

  self.table_name = 'excons'
  self.primary_key = 'id'
end

class LicBusiness < MysqlBase
  has_one :physical_address, -> { where(category: 'Physical') }, :class_name => 'LicExporterAddress', :as => :place
  has_one :mailing_address, -> { where(category: 'Mailing') }, :class_name => 'LicExporterAddress', :as => :place
  has_many :lic_exporter_addresses, :as => :place

  self.table_name = 'businesses'
  self.primary_key = 'id'
end

class LicExporterAddress < MysqlBase
  belongs_to :place, polymorphic: true

  self.table_name = 'addresses'
  self.primary_key = 'id'
end

我们有大量不同类型的业务,因此业务模式是最成问题的。我真的不想在新应用程序中使用它,因为它会让人非常困惑到底什么是“业务”。使用当前代码,如果我进入 rails 控制台并尝试获取 LicBusiness 或 Exporter 的 lic_exporter_addresses,它会:

 SELECT `addresses`.* FROM `addresses` WHERE `addresses`.`place_id` = '00044c693f6848f9b0978f873cf9999a' AND `addresses`.`place_type` = 'LicBusiness'

当我需要的是 place_type = 'Business'。

有没有办法告诉 Rails 去寻找什么 place_type?我确实看到了这个question,第二个答案看起来很有希望,只是我已经在使用物理地址和邮寄地址这样做了,所以我无法弄清楚这两个选项如何同时使用.. . 感谢您提供任何信息或想法。

【问题讨论】:

    标签: ruby-on-rails-4 has-many polymorphic-associations legacy


    【解决方案1】:

    在 Rails 4.2 中,用于查询的确切字符串似乎定义为owner.class.base_class.name,其中owner 是声明关联的模型。所以我不认为它是直接支持的。但是我可以想到几种方法来解决这个问题。我认为最有希望的可能是LicBusiness

    has_many :lic_exporter_addresses, ->{where place_type: "Business"}, foreign_key: "place_id"
    

    即不要将关联定义为多态,而是自己定义类型范围。如果您曾经使用过lic_exporter_address.place = some_lic_business_instance,这将不会在lic_exporter_addresses 表中正确定义place_type。但是你说这个表是只读的,所以这实际上对你来说可能不是问题。如果是,可能有办法覆盖该行为以获得您需要的内容。

    另外两个想法都让我非常紧张,我认为它们可能会产生意想不到的副作用。他们将覆盖LicBusiness.base_class(如果你现在不这样做实际上可能没问题,并且永远不会在LicBusiness上设置STI,但我仍然很紧张),或者覆盖LicBusiness.name(我很确定这会产生意想不到的副作用)。

    【讨论】:

    • 谢谢,这确实有效。这是严格只读的(其他应用程序需要对此数据进行实际管理),所以我不担心 place_type 会为新条目正确填充。对于 physical_address 和 mailing_address 它也有效,例如has_one :physical_address, -> { where(category: 'Physical', place_type: "Business") }, :class_name => 'LicExporterAddress', foreign_key: "place_id"
    猜你喜欢
    • 2014-12-16
    • 2011-03-13
    • 2011-06-06
    • 1970-01-01
    • 2018-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-12
    相关资源
    最近更新 更多