我的表格设置为var outputData = inputData.map( Object.values );
与Child
的{{1}}关系。
他们共享一个主键(1:1
):
Parent
有id
和Parent
以及id
type
有name
和Child
id
是health
的多态继承。我的目标是Child
应该返回Parent
对象,该对象响应Child.find(1)
和Child
。 SQL语句假设看起来像这样:
name
因此,我试图在ActiveRecord中使用多态继承:
health
当我尝试执行SELECT parents.id, parents.name, childs.health FROM parents
LEFT JOIN childs ON childs.id = Parents.id
WHERE parents.id = 1 AND parents.type = 'Child' LIMIT 1
时,我看到:
class Parent < ApplicationRecord
class Child < Parent
值得注意的是,Child.find(1)
表上没有SELECT `parents`.* FROM `parents` WHERE `parents`.`type` IN ('Child') AND `parents`.`ID` = 1 LIMIT 1
=> #<Child id: 1, type: "Child", name: "Hello">
,但我收到了JOIN
个对象。这会导致child
对象不响应Child
的意外行为。奇怪的是,如果我向Child
类(health
)添加显式表关联,则查询模式将更改为:
Child
现在我可以访问self.table_name = "childs"
,但不能访问> c = Child.find(1)
Obtainable Load (0.3ms) SELECT `childs`.* FROM `childs` WHERE `childs`.`ID` = 2 LIMIT 1
或health
。
如何正确创建此JOIN关联,以便尝试加载type
对象成功加入来自父级的数据?
编辑:这些表是在ActiveRecord迁移之外创建的(它们也可以由其他预先存在的非Ruby应用程序访问),因此我无法更改其架构。我可以想到一些奇特的元编程方法,比如响应name
,这可能让我通过连接懒得加载缺少的属性......但我担心我最终还是要重新实现一个一堆ActiveRecord,如Child
,method_missing
等(这将导致错误)。所以我正在寻找一些原生/干净(ish)方法来实现这一目标。
答案 0 :(得分:2)
这不是这里描述的典型Rails多态关联:http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
所以,在这种情况下,当某些其他应用程序先前创建表格时,我建议您执行以下操作:
class Child < ApplicationRecord
self.table_name = "childs"
belongs_to :parent, foreign_key: :id, dependent: :destroy
delegate :name, :type, to: :parent
delegate :name=, to: :parent, allow_nil: true
after_initialize do
self.build_parent(type: "Child") if parent.nil?
end
end
class Parent < ApplicationRecord
self.inheritance_column = 'foo' # otherwise, type column will be used for STI
has_one :child, foreign_key: :id
delegate :health, to: :child
end
现在您可以访问运行状况,类型和名称:
> c = Child.joins(:parent).find(1)
Child Load (0.2ms) SELECT "childs".* FROM "childs" INNER JOIN "parents" ON "parents"."id" = "childs"."id" WHERE "childs"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> #<Child id: 1, health: "Good", created_at: "2016-10-27 21:42:55", updated_at: "2016-10-27 21:44:08">
irb(main):002:0> c.health
=> "Good"
irb(main):003:0> c.type
Parent Load (0.1ms) SELECT "parents".* FROM "parents" WHERE "parents"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> "Child"
irb(main):004:0> c.name
=> "Hello"
,类似于父母:
p = Parent.joins(:child).find(1)
Parent Load (0.1ms) SELECT "parents".* FROM "parents" INNER JOIN "childs" ON "childs"."id" = "parents"."id" WHERE "parents"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> #<Parent id: 1, type: nil, name: "Hello", created_at: "2016-10-27 21:40:35", updated_at: "2016-10-27 21:40:35">
irb(main):003:0> p.name
=> "Hello"
irb(main):004:0> p.health
Child Load (0.1ms) SELECT "childs".* FROM "childs" WHERE "childs"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> "Good"
如果您愿意,可以像这样指定LEFT JOIN:
irb(main):003:0> p = Parent.joins("LEFT JOIN childs ON (childs.id = parents.id)").select("parents.id, parents.name, childs.health").find(1)
Parent Load (0.2ms) SELECT parents.id, parents.name, childs.health FROM "parents" LEFT JOIN childs ON (childs.id = parents.id) WHERE "parents"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> #<Parent id: 1, name: "Hello">
irb(main):004:0> p.name
=> "Hello"
irb(main):005:0> p.health
Child Load (0.1ms) SELECT "childs".* FROM "childs" WHERE "childs"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> "Good"