英文:
Ruby on Rails ActiveRecord Single Table Inheritance has_one to superclass
问题
I have a Base
class which contains STI and named procedures
, looking like this:
class Base < ActiveRecord
self.abstract_class = true
self.table_name = "procedures"
self.inheritance_column = nil
end
We also have multiple superclasses named for instance ProcedureA
and ProcedureB
, looking like this:
class ProcedureA < Base
end
class ProcedureB < Base
end
A procedure can contain another procedure so I'd like to add this to the base class. But when retrieving the other procedure I'd like to know the actual class name. So this works:
class Base < ActiveRecord
self.abstract_class = true
self.table_name = "procedures"
self.inheritance_column = nil
has_one :parent, class_name: "Base"
end
But when retrieving it from the database, it returns it as the Base
class but not the specific class that was assigned.
For instance:
procedure_a = ProcedureA.create!()
procedure_b = ProcedureB.create!()
procedure_a.parent = procedure_b
procedure_a.save!
procedure_a.parent => Is ProcedureB
ProcedureA.first.parent => Is Base class
So at this point, I don't know how to get the actual class instead of the base class. I tried playing with polymorphic: true
but it doesn't work.
英文:
I have a Base
class which contains STI and named procedures
, looking like this:
class Base < ActiveRecord
self.abstract_class = true
self.table_name = "procedures"
self.inheritance_column = nil
end
We also have multiple superclasses named for isntance ProcedureA
and ProcedureB
, looking like this:
class ProcedureA < Base
end
class ProcedureB < Base
end
A procedure can contain another procedure so i'd like to add this to the base class. But when retrieving the other procedure i'd like to know the actual class name. So this works:
class Base < ActiveRecord
self.abstract_class = true
self.table_name = "procedures"
self.inheritance_column = nil
has_one :parent, class_name: "Base"
end
But when retrieving it form the database it returns is as the Base
class but not the specific class that was assigned.
For instance:
procedure_a = ProcedureA.create!()
procedure_b = ProcedureB.create!()
procedure_a.parent = procedure_b
procedure_a.save!
procedure_a.parent => Is ProcedureB
ProcedureA.first.parent => Is Base class
So at this point i don't know how to get the actual class instead of the base class. I tried playing with polymorphic: true
but doesn't work.
答案1
得分: 2
创建一个self referential association时,需要使用belongs_to
而不是has_one
。
class User
belongs_to :manager,
class_name: 'User',
optional: true
has_many :subordinates,
class_name: 'User',
foreign_key: :manager_id
end
毕竟外键是存储在这个模型的表上。
但还有一个问题,即您的Base正在积极地破坏单表继承。它应该是这样的:
class Base < ActiveRecord
self.table_name = "procedures" # 所有子类都将存储在这个表中
end
self.abstract_class = true
告诉ActiveRecord在解析其子类的表名称时忽略此类。这与您的需求相反。
self.inheritance_column = nil
禁用了您需要让单表继承工作的类型推断。
在Rails中,STI的工作方式实际上无需执行任何操作。任何继承自ActiveRecord::Base且不是抽象的类默认都是STI的父类。您只需添加一个type
列,然后子类就能使用了。
添加带有STI的自引用关联与上面的示例几乎相同,但有一个小变化:
class Base < ActiveRecord
belongs_to :parent,
class_name: 'Base',
optional: true
end
class_name: 'Base',
看起来有点奇怪,但实际上只是告诉Rails在哪个表上查找关联的记录。在加载记录时,类型推断将覆盖实例化的类(或者至少在不破坏它的情况下会这样)。
请注意,这不是您需要多态关联的情况。多态关联用于指向多个不同表的单个关联。
英文:
There is a lot of confusion going on here.
To create a self referential assocation you need to use belongs_to
not has_one
.
class User
belongs_to :manager,
class_name: 'User',
optional: true
has_many :subordinates,
class_name: 'User',
foreign_key: :manager_id
end
After all the foreign key is stored on this models table.
But then there is also the fact that your Base is actively sabotaging Single Table Inheritance. It should just read:
class Base < ActiveRecord
self.table_name = "procedures" # all children will be stored in this table
end
self.abstract_class = true
tells ActiveRecord to ignore this class when resolving the table name of its children. That's the opposite of what you want.
self.inheritance_column = nil
disables the type inferance that you need for single table inheritance to work.
The way STI in Rails works you don't actually have to do anything. Any class that inherits from ActiveRecord::Base and is not abstract is a STI parent class by default. All you need to do is add a type
column and subclasses and bob's your uncle.
Adding the self-referential assocation with STI is pretty much the same as above example but with a twist:
class Base < ActiveRecord
belongs_to :parent,
class_name: 'Base',
optional: true
end
class_name: 'Base',
seems kind of odd but its really just telling Rails which table to look for the assocatiated records on. When loading the record the type inferance will override what class is instanciated anyways (or at least it would if you didn't sabotage it).
Note that this is not a case where you want a polymorphic assocation. Thats used when you have a single assocation that points to multiple different tables.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论