【问题标题】:Rails - when to use .reload in code / idiomatic Ruby/Rails codeRails - 何时在代码/惯用的 Ruby/Rails 代码中使用 .reload
【发布时间】:2021-04-09 06:14:30
【问题描述】:

我经常听说.reload 在测试 Rails 应用程序中很常见,但在实际应用程序代码中呢?

下面的代码有效,但我一直在想,在这里使用.reload 是否有点粗糙。特别是因为我正在做的那种操作(通过辅助方法 add_passenger 添加到 has_many 关系,调用 rotate!)看起来很典型。

.reload 的用法可以吗?或者有没有更好的方法来构建我的代码?

    def organize
      Driver.find_each(&:clear_space)

      untaken = Rider.unassigned
      open_drivers = Driver.available

      # assume enough seats for all riders
      while untaken.reload.size > 0
        cur = untaken.first

        open_drivers.reload.each do |driver|
          if cur.prefers_strongest?(driver: driver)
            driver.add_passenger(rider: cur)
          end
        end

        untaken.rotate! if cur.car.nil?
      end

      Car.all
    end
class Driver < Person
  has_one :car, inverse_of: :driver, dependent: :destroy
  delegate :riders, :riders_count, :clear_space, to: :car

  after_create :create_car!

  scope :available, -> { joins(:car).where('riders_count < ?', :total_space) }

  def clear_space
    riders.delete_all if riders_count > 0
  end

  def add_passenger(rider:)
    riders << rider if car.has_space?
  end

  def remove_passenger(rider:) 
    riders.delete(rider) if riders.exists?(rider.id)
  end
end

【问题讨论】:

  • reload 将使用接收到的值进行数据库查询和更新对象。可能的竞争条件可以在不“重新加载”的情况下解决,但这不是一个完美的解决方案。
  • 在这里使用reload 似乎有点笨拙。我想如果你真的想每次都重新运行查询也没关系(尽管我什至没有意识到你可以使用reload 重新运行集合上的查询,所以它可能不是最容易理解的?) .但是,如果您的 untaken 列表永远不会变大,最好将其视为普通列表,并使用 Enumerable / Array 方法根据需要删除元素,而不是重新运行查询
  • 是的@maxpleaner 我同意。如果我确实通过.to_auntakenopen_driver 范围调用(它返回我相信的关系?)转换为数组,我会失去双向能力虽然正确吗?然后我必须手动添加另一行来表示从untaken 骑手数组中删除,一旦其中一个骑手被添加到司机?

标签: ruby-on-rails ruby activerecord model


【解决方案1】:

无需在顶级作用域上调用reload。这些调用不会被缓存。 缓存的是那些通过 ActiveRecord 实例进行的调用。

在这种情况下,您可以使用 reload 丢弃缓存,无论是在整个记录上,还是仅在关联记录上,例如 @user.rides.reload

【讨论】:

  • 这个答案不太正确。 Rails 确实缓存 SQL 调用,例如由“顶级范围”进行的那些 - 它缓存实际的原始 DB 响应,以便当您生成相同的查询时,它使用预设响应。您正确的是 reload 不会避免该缓存 - uncached 会。 guides.rubyonrails.org/caching_with_rails.html#sql-caching
  • 在解释.reload 的作用时,使用“补水”一词也更有帮助。它通过创建一个选择查询来刷新内存中的表示,并从结果中设置对象的任何实例变量。我不会真正将其称为缓存,因为该对象并不是真正打算跨请求缓存数据。
  • 您打算采取的行动是删除所有.reload 电话吗?如果我这样做,那么循环似乎会无限运行(例如,将骑手添加到驱动程序似乎不会更新untaken 骑手列表)。我不应该像这样查询/使用活动记录吗?
  • @max 这很有趣,而且我从来没有意识到,因为这对我来说从来都不是问题。由于在混合中引入了新记录,模型级别的缓存在过去一直存在问题。您想创建自己的答案吗?那可能会更好。
  • 直到在关系上调用#reload 的作用。就像调用 .map(&amp;:reload) 一样,只是它使用单个 SQL 查询重新加载所有记录。 gist.github.com/maxcal/cbf1dc961f2a22506b011d29a27842cc
【解决方案2】:

#reload 实际上只是用于通过执行选择查询来“刷新”或“更新”一条记录或一组记录。因此,很难权威地说一个惯用的用户,因为它实际上只是一个通用工具,可以在需要最新的数据库数据表示时使用。

但是有没有更好的方法来构建我的代码?几乎可以肯定。此处为了简单地安排车内乘客而进出数据库的数据量表明数据建模已关闭,或者您应该考虑一种更简单的解决方案,即先安排数据,然后将数据保存一次,而不是循环。

【讨论】:

  • 啊,我明白了!说得通。您知道我在哪里可以找到有关可能更简单的解决方案的更多信息(例如,将数据“从数据库中”排列出来,然后在完成所有排列/分配后将其保存到数据库中)?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-05
  • 2011-05-20
  • 2012-08-12
  • 2012-09-16
  • 1970-01-01
相关资源
最近更新 更多