Ruby 动态设置子类';s attr';基于数据库/表列的

Ruby 动态设置子类';s attr';基于数据库/表列的,ruby,metaprogramming,subclass,attr,superclass,Ruby,Metaprogramming,Subclass,Attr,Superclass,我需要从数据库中的各个表中检索列名,以便为这些表的相应类动态设置attr\u accessor方法。这需要从父类完成 class Child < Parent attr_accessor :id, :column_a, :etc. end 我的理解是,这本质上应该创建一个从Child到Child.column\u names的调用,我认为它是这样做的。我只是不知道为什么返回数组没有填充。我已经尝试过移动列名方法,但是行为上的唯一变化,取决于它的位置,是子类的命名错误。不幸的是,上的文

我需要从数据库中的各个表中检索列名,以便为这些表的相应类动态设置
attr\u accessor
方法。这需要从父类完成

class Child < Parent
  attr_accessor :id, :column_a, :etc.
end

我的理解是,这本质上应该创建一个从
Child
Child.column\u names
的调用,我认为它是这样做的。我只是不知道为什么返回数组没有填充。我已经尝试过移动
列名
方法,但是行为上的唯一变化,取决于它的位置,是子类的
命名错误。

不幸的是,上的文档不是很详细,但我明白了这里的问题所在-这是
class\u eval
块中
self
的值

NoMethodError是因为未在子类上定义
列名称
方法,而self指的是
类评估
块内的子类

有一个简单的修正,将
self
设置为
class\u eval
块之前的变量

希望在下面的示例中可以清楚地看到这一点,我对此进行了测试并运行良好。请注意,与代码的唯一真正区别在于继承的
方法。所有其他的东西都在测试它,因为我不能按原样运行你的代码

require 'byebug'

class ParentClass
  def self.inherited(child)
    parent_class = self # Store value of self in a variable
                        # because it will change in class_eval
                        # Then call column_names on this variable
    child.class_eval do
        parent_class.column_names.each { |attr| attr_accessor attr.to_sym }
    end
  end
  def self.column_names
    [:foo, :bar]
  end
end

class ChildClass < ParentClass
  def initialize
  end
end

child = ChildClass.new
child.foo = "bar"
puts child.foo
# => "bar"
需要“byebug”
类父类
def self.inherited(子项)
parent_class=self#将self的值存储在变量中
#因为它会在课堂上改变
#然后调用此变量的列名称
child.class\u eval do
parent|class.column_names.each{| attr | attr_访问器attr.to_sym}
结束
结束
def self.column_名称
[:foo,:bar]
结束
结束
类ChildClass<父类
def初始化
结束
结束
child=ChildClass.new
child.foo=“bar”
放置child.foo
#=>“巴”

这个问题在javascript中更为常见,javascript具有更严格的范围级别隔离。换句话说,
self
的值变化更频繁

你能给出一个模块的使用示例吗?@max pleaner该模块基本上是一个ORM-只是ActiveRecord的超轻版本。我试了一下,但没有骰子。它可以工作,这意味着它确实成功地调用了正确的column_names方法,如果手动填充返回数组也没关系。但是从继承的
方法中调用它仍然会使数组为空。如果我移动
#column_name
方法,我只会得到
NoMethodError
。我已经改变了方法,可以在填充数组后调用attr_setter方法,但对我来说仍然是个谜,为什么直接调用#column_names会使其为空。也许可以尝试检查表名是否返回正确的值?您应该使用调试器并逐步完成列名方法。
require 'byebug'

class ParentClass
  def self.inherited(child)
    parent_class = self # Store value of self in a variable
                        # because it will change in class_eval
                        # Then call column_names on this variable
    child.class_eval do
        parent_class.column_names.each { |attr| attr_accessor attr.to_sym }
    end
  end
  def self.column_names
    [:foo, :bar]
  end
end

class ChildClass < ParentClass
  def initialize
  end
end

child = ChildClass.new
child.foo = "bar"
puts child.foo
# => "bar"