ruby-on-rails Rails 5如何在多个共享属性的表之间形成关联

jchrr9hc  于 2023-01-06  发布在  Ruby
关注(0)|答案(1)|浏览(204)

在Rails5中,给定两个表之间的关系,该关系涉及在多个共享属性上连接它们,如何在与这些表对应的模型之间形成关联?
SQL语句:

SELECT *
FROM trips
JOIN stop_times ON trips.guid = stop_times.trip_guid AND trips.schedule_id = stop_times.schedule_id

我尝试了以下配置,它的工作一般...

class Trip < ApplicationRecord
  has_many :stop_times, ->(trip){ where("stop_times.schedule_id = ?", trip.schedule_id) }, :inverse_of => :trip, :primary_key => :guid, :foreign_key => :trip_guid, :dependent => :destroy
end

class StopTime < ApplicationRecord
  belongs_to :trip, :inverse_of => :stop_times, :primary_key => :guid, :foreign_key => :trip_guid
end

Trip.first.stop_times.first #> StopTime object, as expected
Trip.first.stop_times.first.trip #> Trip object, as expected

...但是当我尝试在更高级的查询中使用它时,它触发了 * ArgumentError:关联范围"stop_times"依赖于示例(范围块采用参数)。不支持预加载依赖于示例的范围。*...

Trip.joins(:stop_times).first #=> the unexpected ArgumentError
StopTime.joins(:trip).first #> StopTime object, as expected

我知道这个错误指的是什么,但我不确定如何修复它。
编辑:
我希望一个单一的协会将是足够的,但已经注意到两个不同的协会可以做这项工作:

class Trip < ApplicationRecord
  has_many :stop_times, 
              ->(trip){ where("stop_times.schedule_id = ?", trip.schedule_id) }, 
              :primary_key => :guid, 
              :foreign_key => :trip_guid # use trip.stop_times instead of trip.joined_stop_times to avoid error about missing attribute due to missing join clause

  has_many :joined_stop_times, 
            ->{ where("stop_times.schedule_id = trips.schedule_id") },
            :class_name => "StopTime",
            :primary_key => :guid,
            :foreign_key => :trip_guid # use joins(:joined_stop_times) instead of joins(:stop_times) to avoid error about instance-specific association
end

Trip.first.stop_times
Trip.eager_load(:joined_stop_times).to_a.first.joined_stop_times # executes a single query

如果任何人读到这篇文章知道如何使用一个单一的联想,请提到我。

xkrw2x1b

xkrw2x1b1#

我不认为这是正确的解决方案,但它可以帮助。您可以添加另一个类似的示例独立关联,它将只用于预加载。它将适用于:joins:eager_load,但不适用于:preload
请注意,:includes可能在内部使用:eager_load:preload。因此,:includes并不总是与该关联一起工作。您应该显式使用:eager_load

class Trip < ApplicationRecord
  has_many :preloaded_stop_times, 
           -> { where("stop_times.schedule_id = trips.schedule_id") },               
           class_name: "StopTime", 
           primary_key: :guid, 
           foreign_key: :trip_guid
end

# Usage
trips = Trip.joins(:preloaded_stop_times).where(...)
# ...

# with :eager_load
trips = Trip.eager_load(:preloaded_stop_times)

trips.each do |trip|
  stop_times = trip.preloaded_stop_times
  # ...
end

相关问题