ruby-on-rails – Rails 4.2:渴望加载与STI的has_many关系

ruby-on-rails – Rails 4.2:渴望加载与STI的has_many关系,第1张

概述假设我在Rails中与使用STI的表有关系,如: class Vehicle < ActiveRecord::Base; endclass Car < Vehicle; endclass Truck < Vehicle; endclass Person < ActiveRecord::Base has_many :cars has_many :trucks has_many 假设我在Rails中与使用STI的表有关系,如:

@H_419_8@

@H_419_8@

class Vehicle < ActiveRecord::Base; endclass Car < Vehicle; endclass Truck < Vehicle; endclass Person < ActiveRecord::Base  has_many :cars  has_many :trucks  has_many :vehiclesend

…我想在一个查询中加载一个人及其所有汽车和卡车.这不起作用:@H_419_8@

@H_419_8@

# Generates three querIEsp = Person.includes([:cars,trucks]).first

……这很接近,但这里没有运气:@H_419_8@

@H_419_8@

# Preloads vehicles in one queryp = Person.includes(:vehicles).first# and this has the correct class (Car or Truck)p.vehicles.first# but this still runs another queryp.cars

我可以在person.rb做这样的事情:@H_419_8@

@H_419_8@

def cars  vehicles.find_all { |v| v.is_a? Car }end

但是Person#cars不再是集合代理了,我喜欢集合代理.@H_419_8@

有一个优雅的解决方案吗?@H_419_8@

编辑:将此添加到Person给我带有一个查询的数组中我想要的项目;它真的非常接近我想要的东西:@H_419_8@

@H_419_8@

def vehicle_hash  @vehicle_hash ||= vehicles.group_by {|v|    v.type.tableize  }end%w(cars trucks).each do |assoc|  define_method "#{assoc}_from_hash".to_sym do    vehicle_hash[assoc] || []  endend

现在我可以做Person.first.cars_from_hash(或者为我的非合成用例找到一个更好的名字).@H_419_8@解决方法 当您使用includes时,它会将这些已加载的记录存储在association_cache中,您可以在控制台中查看.当您执行p = Person.includes(:vehicles)时,它会将这些记录存储为密钥:vehicles下的关联.它使用您在包含中传递的任何键.

@H_419_8@

那么当你调用p.cars时,它注意到它在association_cache中没有:cars键并且必须查找它们.它没有意识到汽车被混合到:车辆钥匙.@H_419_8@

为了能够通过p.vehicles OR p.cars访问缓存的汽车,需要在这两个密钥下缓存它们.@H_419_8@

它存储的不仅仅是一个简单的数组 – 它是一个关系.因此,您不能只在Hash中手动存储记录.@H_419_8@

在你提出的解决方案中,我认为包含每个密钥可能是最简单的代码. Person.includes(:cars,:trucks)3如果你每次请求只做一次,那么SQL语句就不那么糟了.@H_419_8@

如果性能是一个问题,我认为最简单的解决方案将与您的建议非常相似.我可能会写一个新方法find_all_cars而不是覆盖关系方法.@H_419_8@

虽然,我可能会覆盖车辆,并允许它采取类型参数:@H_419_8@

@H_419_8@

def vehicles(sti_type=nil)  return super unless sti_type  super.find_all { |v| v.type == sti_type }end

编辑@H_419_8@

你可以获得Rails缓存的车辆,所以你可能只能依赖它.您的define_methods也可以这样做:@H_419_8@

@H_419_8@

%w(cars trucks).each do |assoc|  define_method "preloaded_#{assoc}" do    klass = self.class.reflect_on_all_associations.detect { |assn| assn.name.to_s == assoc }.klass    vehicles.select { |a| a.is_a? klass }  endend

即使您不使用包含,第一次调用它时,它也会缓存关联 – 因为您选择的是,而不是在哪里.当然,你仍然不会得到一个关系.@H_419_8@

它并不是那么漂亮,但我喜欢它包含在一个不依赖于任何其他方法的方法中.@H_419_8@ 总结

以上是内存溢出为你收集整理的ruby-on-rails – Rails 4.2:渴望加载与STI的has_many关系全部内容,希望文章能够帮你解决ruby-on-rails – Rails 4.2:渴望加载与STI的has_many关系所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1276610.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-09
下一篇 2022-06-09

发表评论

登录后才能评论

评论列表(0条)

保存