如何在模型中编写更高效的代码?

How to make more efficient code in model?

有重构方法 self.import_data 代码的想法吗?这是一种允许应用程序将 CSV 文件保存在数据库中的方法(对用户电子邮件有一些限制)。应该是每天中午运行,所以一定要快。 当我有一个大的 CSV 文件时,目前它很长到 运行。我想知道是否有办法让这段代码更有效率并赢得一些时间(或者避免循环或减少请求......)。我真的不知道是什么让这个过程实际上如此漫长以及如何纠正它。

这是我的模型:

class Person < ActiveRecord::Base
  has_paper_trail
  validates :email,  uniqueness: true
  require 'csv'

  def is_former_email?(update_email)
    self.versions.each do |version|
      next if version.object.nil?
      return true if version.object.include?(update_email)
    end
  end

 def self.import_data
   filename = File.join Rails.root, '/vendor/people.csv'

   CSV.foreach(filename, headers: true, col_sep: ',') do  |row|
     firstname, lastname, home_phone_number, mobile_phone_number, email, address = row

     person = Person.find_or_create_by(firstname: row["firstname"], lastname: row['lastname'], address: row['address'] )
     if person.is_former_email?(row['email']) == true
       puts "not allowed"
     else
       person.update_attributes({firstname: row['firstname'], lastname: row['lastname'], home_phone_number: row['home_phone_number'], mobile_phone_number: row['mobile_phone_number'], address: row['address'], email: row['email']})
     end
    end
  end
end

我稍微重构了你的代码,但为了更有效,我建议使用 gem activerecord-import 并优化版本模型以搜索以前的电子邮件。

class Person < ActiveRecord::Base
  require 'csv'

  FILE_NAME = File.join Rails.root, '/vendor/people.csv'

  validates :email, uniqueness: true

  has_paper_trail

  def self.import_data
    people = CSV.new(File.new(FILE_NAME), headers: true, header_converters: :symbol, converters: :all).to_a.map(&:to_hash)
    versions_by_item_id = Version.where(item_type: 'Person').select('item_id, object').group_by(&:item_id)

    people.each do |person_params|
      person = Person.find_or_create_by(person_params.slice(:firstname, :lastname, :address))
      if versions_by_item_id[person.id] && versions_by_item_id[person.id].sum { |v| v.object.to_s }.include?(person_params[:email])
        puts 'not allowed'
      else
        person.update_attributes(person_params.slice(:home_phone_number, :mobile_phone_number, :email))
      end
    end
  end
end