You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby/Rails 数据库查询低级缓存实现问题求助

解决Rails首页24小时低级缓存仅一次数据库请求的问题

我明白你想实现的需求:让首页未过滤的情况下每天只触发一次数据库查询,用低级缓存来达成这个目标。咱们一步步拆解你代码里的问题,然后给出可行的解决方案。

先说说你之前代码里的核心问题

第一个版本代码的问题

你最初尝试把Freelancer.order(featured: :desc)这个ActiveRecord关系缓存起来,但ActiveRecord关系并不是实际的数据,它只是查询语句的构建器。缓存关系对象不会执行数据库查询,每次你使用这个关系时,还是会触发新的数据库请求,完全达不到缓存的目的。另外,你的index方法没有接收freelancers_scope参数,导致freelancers_scope始终是nil,会无限递归调用cache方法,这肯定会报错。

更新后代码的问题

你改成缓存哈希数组的思路是对的,但细节上有问题:

  • 用map(&:attributes)把模型对象转成哈希,会丢失模型的方法和关联,后续如果需要调用模型的业务逻辑会很麻烦;
  • 过滤逻辑里的条件搞反了,而且params[:cost_greater_than].presence如果为nil的话,会生成无效的范围(比如(0..nil)),直接导致报错;
  • 没有处理参数类型转换,字符串和数字比较可能会出问题。

正确的实现方式

下面是修正后的代码,每一步我都加了注释说明:

class HomeController < ApplicationController
  before_action :set_freelancer, only: %i[ show edit update destroy ]

  def index
    # 缓存原始的Freelancer列表,24小时过期
    # 使用.to_a获取实际的记录数组,而不是ActiveRecord关系,这样缓存的是真实数据
    base_freelancers = Rails.cache.fetch('freelancers', expires_in: 24.hours) do
      Freelancer.order(featured: :desc).to_a
    end

    # 复制原始数组,避免修改缓存中的数据
    filtered_freelancers = base_freelancers.dup

    # 处理「最低成本」过滤:cost >= 传入的最小值
    if params[:cost_greater_than].present?
      min_cost = params[:cost_greater_than].to_i
      filtered_freelancers = filtered_freelancers.select { |freelancer| freelancer.cost >= min_cost }
    end

    # 处理「最高成本」过滤:cost <= 传入的最大值
    if params[:cost_lower_than].present?
      max_cost = params[:cost_lower_than].to_i
      filtered_freelancers = filtered_freelancers.select { |freelancer| freelancer.cost <= max_cost }
    end

    # 用pagy_array处理数组分页,和你之前的用法一致
    @pagy, @freelancers = pagy_array(filtered_freelancers)
  end

  private
    def set_freelancer
      @freelancer = Freelancer.find(params[:id])
    end
end

关键要点说明

  1. 缓存实际数据而非查询关系:用.to_a让ActiveRecord立即执行查询并返回记录数组,这样缓存的是真实的数据集,24小时内不会再触发数据库查询。
  2. 正确处理过滤逻辑:修正了参数和条件的对应关系,同时做了类型转换,避免字符串和数字比较的问题;复制数组是为了保证缓存的原始数据不被修改,确保后续请求的缓存一致性。
  3. 保留模型对象:直接缓存模型实例数组,而不是哈希,这样后续如果需要调用模型的方法(比如freelancer.full_name)依然可以正常使用。

这样修改后,就能实现你想要的:未过滤的首页每天仅发起一次数据库请求,过滤请求则基于缓存的数据在内存中处理,完全符合你的需求。

内容的提问来源于stack exchange,提问作者Luke Czoboriek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 00:17:40