基于 class 名称的 Ruby sqlite 查询中的动态 table 名称

Dynamic table name in Ruby sqlite query based on class name

我有一个 parent class 看起来像这样:

class Record
  attr_accessor :id, :url, :votes, :title, :first_name, :last_name, :selfdb

  def initialize(args = {})
    args.each { |name, value| instance_variable_set("@#{name}", value) }
    @selfdb = "#{self.class.name.downcase}s"
  end

  def self.find(id)
    DB.results_as_hash = true
    hasharray = DB.execute("SELECT * FROM ? WHERE id = ?", @selfdb, id)
    hasharray.empty? ? nil : new(hasharray[0].transform_keys(&:to_sym))
  end
end

记录的每个 child class 都有一个匹配的数据库 table 其名称是“#{name of the class}”,因此 class “Post”连接到名为“posts”的 table。

我的目标是让 self.find(id) 处理此 class 的任何 children。我尝试的解决方案是将 class' 名称保存到末尾带有“s”的字符串变量中(例如 class Post -> “posts”),匹配数据库的名称,正如我在实例变量@selfdb 中尝试的那样,但这不起作用。

在 children classes 上调用 @selfdb 确认它确实为不同的 classes 正确创建了字符串,但是 运行 插入了它的 sqlite作为 table 名称只是 returns 零。

这可能是一种非常迂回的做法,欢迎任何建议。我还在学习,这只是训练营作业。

编辑:我意识到我犯了一个错误:因为 self.find(id) 是一个 class 方法,它不能使用实例变量。但是,当我将 class 方法更改为这样工作时:

def self.find(id)
    selfdb = "#{self.name.downcase}s"
    DB.results_as_hash = true
    hasharray = DB.execute("SELECT * FROM ? WHERE id = ?", selfdb, id)
    hasharray.empty? ? nil : new(hasharray[0].transform_keys(&:to_sym))
end

...它仍然没有正确插入到 sqlite 字符串中。

您在初始化方法中定义了 @selfdb,这意味着它仅在实例级别可用。但是您的 self.find 方法是 class 方法,因此 @selfdb 在 class 级别未定义。

我建议添加一个 class 方法,returns table 这样的名称

def self.table_name
  "#{name.downcase}s"
end

然后您可以像这样在 find class 方法中使用它

def self.find(id)
  # ...
  hasharray = DB.execute("SELECT * FROM ? WHERE id = ?", table_name, id)
  # ...
end

并且在实例方法(例如保存记录)中,您需要使用 self.class.table_name 或者您可以添加委托人将 table_name 实例方法调用转发给 class方法:

extend Forwardable
def_delegators :"self.class", :table_name