【问题标题】:How can I upsert a bunch of ActiveRecord objects and relationships in Rails?如何在 Rails 中插入一堆 ActiveRecord 对象和关系?
【发布时间】:2008-09-07 08:10:00
【问题描述】:

我正在使用一个提供巴士到达数据的 API。对于每个请求,我都会(除其他外)返回一个列表,其中列出了哪些路线服务于相关站点。例如,如果列表中包含公交路线 #1、2 和 5 的结果,那么我知道那些服务于该站点。

我在 Route 和 Stop 之间建立了多对多关系,我想在每个请求上动态检查和更新这些关联。没有关于哪些路线服务哪些站点的“主列表”,因此这似乎是获取这些数据的最佳方式。

我相信我现在这样做的方式非常低效:

# routes is an array of [number, destination] that I build while iterating over the data
routes.uniq.each do |route|
  number      = route[0]
  destination = route[1]

  r = Route.find_by_number_and_destination(number, destination)

  if !r
    r = Route.new :number => number, :destination => destination
    r.save
  end

  # I have to check if it already exists because I can't find a way
  # to create a uniqueness constraint on the join table with 2 foreign keys
  r.stops << stop unless r.stops.include? stop
end

基本上,我必须为找到的每条路线做两件事: 1) 如果它不存在,则创建它,2) 如果它不存在,则添加到当前停靠点的关系。

有没有更好的方法来做到这一点,例如通过在内存中获取一堆数据并在应用服务器端进行一些处理,以避免我目前正在进行的大量数据库调用?

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    如果我猜对了,你(应该)有 2 个模型。 Route 模型和 Stop 模型。

    我会这样定义这些模型:

    class Route < ActiveRecord::Base
      has_and_belongs_to_many :stops
      belongs_to :stop, :foreign_key => 'destination_id'
    end
    
    class Stop < ActiveRecorde::Base
      has_and_belongs_to_many :routes
    end
    

    以下是我设置表格的方式:

    create_table :routes do |t|
      t.integer :destination_id
      # Any other information you want to store about routes
    end
    
    create_table :stops do |t|
      # Any other information you want to store about stops
    end
    
    create_table :routes_stops, :primary_key => [:route_id, :stop_id] do |t|
      t.integer :route_id
      t.integer :stop_id
    end
    

    最后,这是我要使用的代码:

    # First, find all the relevant routes, just for caching.
    Route.find(numbers)
    
    r = Route.find(number)
    r.destination_id = destination
    r.stops << stop
    

    这应该只使用几个 SQL 查询。

    【讨论】:

      【解决方案2】:

      试试这个宝石: https://github.com/seamusabshere/upsert

      文档说它比 find_or_create_by 快 80%

      【讨论】:

        【解决方案3】:

        可能有一种清理停靠点呼叫的好方法,但假设我正确地描绘了路线的结构,这会清理很多。

        routes.uniq.each do |number, destination|
        
          r = Route.find_or_create_by_number_and_destination(route[0], destination)
        
          r.stops << stop unless r.stops.include? stop
        
        end
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-07-12
          • 2021-12-08
          • 1970-01-01
          • 1970-01-01
          • 2015-12-23
          相关资源
          最近更新 更多