Rails - 如何在执行检测方法时避免使用数据库?

时间:2016-11-19 13:11:43

标签: ruby-on-rails activerecord

在int数组上执行detect时,它可以工作:

@number = [1,2,3,4,5,6,7].detect{|n| n == 4}

变量@number变为4。

但是当我做这样的事情时:

@categories = Category.all
@current_category = @categories.detect{|cat| cat.id == params[:category]}

程序输出

Category Load (0.2ms) SELECT "categories".* FROM "categories"

这意味着它正在使用数据库来查找它。

但是,我试图找到的元素已经在集合@categories中,我只想找到它以将其分配给变量。

当然,另一种解决方案是实现线性搜索算法,但我只想保持代码尽可能干净。

如何避免使用数据库进行此搜索?

编辑:我刚刚意识到这可能是懒惰的提取。因为在detect之前,我从不使用@categories,所以当我执行detect时它会执行查询。这可能是真的吗?

2 个答案:

答案 0 :(得分:1)

当您调用SELECT COUNT(*)时,Rails实际上正在执行@categories.all查询,实质上是执行延迟抓取。

您的@categories对象仍需要在数据库中查询数据。

请参阅此处的文档:http://apidock.com/rails/ActiveRecord/Scoping/Named/ClassMethods/all

posts = Post.all
posts.size # Fires "select count(*) from  posts" and returns the count
posts.each {|p| puts p.name } # Fires "select * from posts" and loads post objects

fruits = Fruit.all
fruits = fruits.where(color: 'red') if options[:red_only]
fruits = fruits.limit(10) if limited?

答案 1 :(得分:0)

在您的情况下,您应该使用活动记录和SQL请求。

@current_category = @categories.find_by(id: params[:category])

在Active Record关系上使用数组方法倾向于获取所有数据然后将算法应用于内存中,而SQL过滤更快。

在你的情况下,我喜欢在我的模型上定义运算符[]

#in category.rb
def self.[](x)
  self.find_by(id: x)
end

# anywhere after:
if c = Category[params[:id]]
  puts "Category found and it's #{c.name} !"
else
  puts "Not found :("
end