Rails:更新除了最近创建的所有内容之外的所有内容

时间:2017-10-03 00:23:11

标签: ruby-on-rails activerecord ruby-on-rails-5

我有两个班级:

class Account
  has_many :follow_ups
end

class FollowUp
  belongs_to :account
end

对于每个帐户,我都需要在completed_at上引入FollowUp列。我还需要为每个帐户执行以下操作:将completed_at设置为1900年1月1日,除了最近创建的后续操作之外的每个后续操作。

我尝试将以下内容放入一个迁移文件中,但它将所有FollowUp s completed_at保留为nil

class AddCompletedAtToFollowUps < ActiveRecord::Migration[5.1]
  def change
    add_column :follow_ups, :completed_at, :datetime

    set_all_but_most_recent_follow_ups_as_long_completed_for_each_account
  end

  private

  def set_all_but_most_recent_follow_ups_as_long_completed_for_each_account
    Account.all.each do |account|
      all_but_most_recent_follow_up_for(account).find_each do |follow_up|
        follow_up.update(completed_at: Time.utc(1900))
      end
    end
  end

  def all_but_most_recent_follow_up_for(account)
    account.follow_ups.order(created_at: :desc).offset(1)
  end
end

我知道这是一个可怕的O(n ^ 2)设置,但令我惊讶的是它甚至无法正常工作。

有人可以帮助我实现最快的查询吗?

P.S。 all_but_most_recent_follow_up_for(account).update_all更新了FollowUps所有,这也是错误的。

2 个答案:

答案 0 :(得分:0)

以下似乎运作良好。 (但我怀疑有更高效的东西,也许是避免迭代的东西。)

%

答案 1 :(得分:0)

如果您不介意使用大量SQL,可以使用OFFSET子句:

class AddCompletedAtToFollowUps < ActiveRecord::Migration[5.1]
  def change
    add_column :follow_ups, :completed_at, :datetime
    Account.find_each do |a| 
      FollowUp.update_all("completed_at = '#{Time.utc(1900)}' where id in (select id from follow_ups where account_id = #{a.id} order by created_at desc offset 1)")
    end
  end
end