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

Ruby on Rails如何查询数据库生成药品-商家价格对比表?

解决药品价格对比表格的查询与视图问题

你的原视图代码有两个核心问题:一是每次循环都触发单独的数据库查询(N+1性能问题),效率极低;二是如果某个药品在某家药店没有价格记录时,find_by_pharmacy_id会返回nil,调用.price就会抛出错误。下面是优化后的完整方案:

第一步:优化控制器的数据加载(避免N+1查询)

我们可以提前预加载所有需要的价格数据,并且整理成方便视图调用的结构,这样视图里就不用再单独查数据库了:

pharmacy = Pharmacy.find(params[:id])
longitude = pharmacy.x
latitude = pharmacy.y
@competitors = Pharmacy.where(x: (longitude-0.005..longitude+0.005), y: (latitude-0.005..latitude+0.005))
competitor_ids = @competitors.pluck(:id)

# 预加载药品及其对应的竞争药店价格,同时整理价格映射
@drugs = Drug.all.sort_by(&:name).includes(:drug_pharmacies).map do |drug|
  # 过滤出当前药品在竞争药店的价格记录,并按药店ID索引
  price_map = drug.drug_pharmacies.where(pharmacy_id: competitor_ids).index_by(&:pharmacy_id)
  # 给药品对象动态添加一个方法,方便视图快速获取对应药店的价格
  def drug.price_for(pharmacy_id)
    # 从临时存储的price_map中取价格,没有的话返回自定义文本(比如"无")
    price_entry = instance_variable_get(:@price_map)[pharmacy_id]
    price_entry&.price || "无"
  end
  # 把price_map存为药品对象的临时变量
  drug.instance_variable_set(:@price_map, price_map)
  drug
end

第二步:修正视图代码(更简洁且容错)

现在视图可以直接遍历竞争药店,调用我们添加的price_for方法,不用再手动处理索引和查询:

<table>
  <tr>
    <th>药品名称</th>
    <% @competitors.each do |apteka| %>
    <th><%= apteka.name %></th>
    <% end %>
  </tr>
  <% @drugs.each do |drug| %>
  <tr>
    <td><%= drug.name %></td>
    <% @competitors.each do |apteka| %>
    <td><%= drug.price_for(apteka.id) %></td>
    <% end %>
  </tr>
  <% end %>
</table>

可选:用数据库聚合查询优化(另一种思路)

如果你希望更直接地从数据库获取结构化数据,可以用joins和group_by来整理:

# 控制器中获取结构化的价格数据
pharmacy = Pharmacy.find(params[:id])
longitude = pharmacy.x
latitude = pharmacy.y
@competitors = Pharmacy.where(x: (longitude-0.005..longitude+0.005), y: (latitude-0.005..latitude+0.005))
competitor_ids = @competitors.pluck(:id)

@drugs = Drug.all.order(:name)
# 查询所有药品在竞争药店的价格,并按药品ID分组
price_data = DrugPharmacy.where(pharmacy_id: competitor_ids, drug_id: @drugs.pluck(:id))
                         .select(:drug_id, :pharmacy_id, :price)
                         .group_by(&:drug_id)
# 把价格数据转换成 {drug_id => {pharmacy_id => price}} 的哈希
@price_hash = price_data.transform_values do |entries|
  entries.index_by(&:pharmacy_id).transform_values(&:price)
end

对应的视图代码:

<table>
  <tr>
    <th>药品名称</th>
    <% @competitors.each do |apteka| %>
    <th><%= apteka.name %></th>
    <% end %>
  </tr>
  <% @drugs.each do |drug| %>
  <tr>
    <td><%= drug.name %></td>
    <% @competitors.each do |apteka| %>
    <td><%= @price_hash[drug.id]&.[](apteka.id) || "无" %></td>
    <% end %>
  </tr>
  <% end %>
</table>

这两种方案都能解决你的问题,第一种更面向对象,第二种更偏向数据驱动,你可以根据自己的习惯选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:21:12