【问题标题】:Ruby on Rails: ActiveRecord-like queries on non-persisted objects?Ruby on Rails:对非持久对象的类似 ActiveRecord 的查询?
【发布时间】:2017-03-10 21:13:38
【问题描述】:

在我的项目中,大量的 PORO 是由外部 API 等各种数据源组成的。对象看起来像:

{id: 1, name: 'Peter', age: 8}, {id: 2, name: 'Jack', age: 4}, {id: 3, name: 'Tom', age: 12}

我想要一个类似 ActiveRecord 的接口来查询这些对象。如Person.where(name: 'Jack')Person.where("age > ?", 5)

我的尝试如下所示:

class Query
    def initialize(objs)
      @objs = objs
    end

    def where(name: nil, age: nil)
      result = @objs 
      result = result.select{|x| x.name == name} if name
      result = result.select{|x| x.age == age}   if age
      result
    end
end

它有效,但我认为这不是一个好的解决方案:

  1. 如果有 20 个属性怎么办? where 方法可能会变得很长且容易出错。
  2. 其他有用的 ActiveRecord 查询呢?例如findfind_bypluckorder by 等等。即使我可以全部实现它们,我如何“链接”多个查询?
  3. 效率:如何像 sql 查询规划器一样优化查询?
  4. 最重要的是,如何实现Person.where("age > ?", 5) 和其他灵活查询?

我错过了什么吗?我觉得我在重新发明轮子。

我检查过 ActiveModel,但不幸的是它没有查询系统。

有什么可以提供帮助的宝石吗?

【问题讨论】:

  • 复制where 的功能可能是一项合理的工作,但是为内存中的对象重新创建整个 ActiveRecord 查询接口将是一项艰巨的任务。这不是 StackOverflow 问题的好主题。
  • 你是对的。我不想实现 ActiveRecord 接口;我正在寻找可以为我完成繁重工作的宝石或工具。

标签: sql ruby-on-rails ruby activerecord activemodel


【解决方案1】:

您最好使用对象映射器,例如来自https://www.ruby-toolbox.com/categories/orm 的映射器。 http://rom-rb.org/learn/repositories/reading-simple-objects/ 显示了一个示例实现,但这对于您正在做的事情可能有点过头了。

Hashie 支持诸如 deep_find 用于单个对象和 deep_locate 用于对象集合的方法。 deep_locate 可能适用于您正在做的事情,但请记住,Hashie 对象将占用比标准哈希更多的内存。

deep_locate 的示例代码:

books = [
  {
    title: "Ruby for beginners",
    pages: 120
  },
  {
    title: "CSS for intermediates",
    pages: 80
  },
  {
    title: "Collection of ruby books",
    books: [
      {
        title: "Ruby for the rest of us",
        pages: 576
      }
    ]
  }
]

books.extend(Hashie::Extensions::DeepLocate)

# for ruby 1.9 leave *no* space between the lambda rocket and the braces
# http://ruby-journal.com/becareful-with-space-in-lambda-hash-rocket-syntax-between-ruby-1-dot-9-and-2-dot-0/

books.deep_locate -> (key, value, object) { key == :title && value.include?("Ruby") }
# => [{:title=>"Ruby for beginners", :pages=>120}, {:title=>"Ruby for the rest of us", :pages=>576}]

books.deep_locate -> (key, value, object) { key == :pages && value <= 120 }
# => [{:title=>"Ruby for beginners", :pages=>120}, {:title=>"CSS for intermediates", :pages=>80}]

【讨论】:

    猜你喜欢
    • 2012-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    相关资源
    最近更新 更多