从父类inheritance类定义

我正在我的Rails模型中构建Grape Entities,如下所述:

https://github.com/ruby-grape/grape-entity#entity-organization

目前,我正在根据模型本身的列哈希自动创建默认值。

所以我有一个静态的get_entity方法,它暴露了所有模型的列:

class ApplicationRecord < ActiveRecord::Base def self.get_entity(target) self.columns_hash.each do |name, column| target.expose name, documentation: { desc: "Col #{name} of #{self.to_s}" } end end end 

然后我在这里有一个示例Book模型在声明的Entity子类中使用它(注释还显示了我如何覆盖模型列之一的文档):

 class Book < ActiveRecord::Base class Entity < Grape::Entity Book::get_entity(self) # expose :some_column, documentation: {desc: "this is an override"} end end 

这种方法的缺点是我总是需要在我想要实体的每个模型中复制和粘贴类Entity声明。

任何人都可以帮我自动为ApplicationRecord的所有子项生成类Entity吗? 然后,如果我需要覆盖,我将需要在类中具有Entity声明,否则如果默认声明足够并且可以保持原样。

注意:

我不能直接在ApplicationRecord中添加类Entity定义,因为Entity类应该调用get_entity,get_entity依赖于Books的column_hash。

解:

最后这样做归功于脑袋:

 def self.inherited(subclass) super # definition of Entity entity = Class.new(Grape::Entity) entity.class_eval do subclass.get_entity(entity) end subclass.const_set "Entity", entity # definition of EntityList entity_list = Class.new(Grape::Entity) entity_list.class_eval do expose :items, with: subclass::Entity expose :meta, with: V1::Entities::Meta end subclass.const_set "EntityList", entity_list end def self.get_entity(entity) model = self model.columns_hash.each do |name, column| entity.expose name, documentation: { type: "#{V1::Base::get_grape_type(column.type)}", desc: "The column #{name} of the #{model.to_s.underscore.humanize.downcase}" } end end 

谢谢!

我没有使用过Grape,所以你可能需要一些我不知道的额外魔法,但这在Ruby / Rails中很容易实现。 根据您的问题“自动生成ApplicationRecord的所有子项的类实体”,您可以这样做:

 class ApplicationRecord < ActiveRecord::Base self.abstract_class = true class Entity < Grape::Entity # whatever shared stuff you want end end 

然后,Book可以访问父Entity

 > Book::Entity => ApplicationRecord::Entity 

如果您只想向Book::Entity添加额外的代码,您可以在Book对其进行子类化,如下所示:

 class Book < ApplicationRecord class Entity < Entity # subclasses the parent Entity, don't forget this # whatever Book-specific stuff you want end end 

然后Book::Entity将是它自己的类。

 > Book::Entity => Book::Entity 

要将此与您在inheritance类上调用get_entity的需求相结合,您可以使用#inherited方法在ApplicationRecord被子类化时自动调用get_entity

 class ApplicationRecord < ActiveRecord::Base self.abstract_class = true def self.get_entity(target) target.columns_hash.each do |name, column| target.expose name, documentation: { desc: "Col #{name} of #{self.to_s}" } end end def self.inherited(subclass) super get_entity(subclass) end class Entity < Grape::Entity # whatever shared stuff you want end end