Ruby on Rails:对非持久化对象的类似ActiveRecord的查询?

时间:2017-03-10 21:13:39

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

在我的项目中,大量的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)和其他灵活查询?
  5. 我错过了什么吗?我觉得我正在重新发明轮子。

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

    那里有没有可以提供帮助的宝石?

1 个答案:

答案 0 :(得分: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}]