如何在模型中创建更高效​​的代码?

时间:2016-07-15 07:06:44

标签: performance ruby-on-rails-4 model refactoring import-from-csv

有没有想过重构方法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

1 个答案:

答案 0 :(得分:2)

我对您的代码进行了一些重构,但为了更有效率,我建议使用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