FasterCSV: check if a file is invalid before accepting it - is there an easier way?

I use FasterCSV in a Ruby on Rails application, and currently it throws an exception if the file is invalid.

I looked at the FasterCSV document and it seems that if I use FasterCSV :: parse with a block, it will read the file one line at a time, without allocating too much memory. This will throw a FasterCSV :: MalformedCSV exception if there is any error in the file.

I have implemented my own solution, but I'm not sure if this is the best (see my answer below). I would be interested to know the alternatives

+3
source share
3 answers

, , ; CSV is_valid. , FasterCSV - , , , safe_parse:

#/lib/faster_csv_safe_parse.rb
class FasterCSV

  def self.safe_parse(file, options = {})
    begin
      FasterCSV.parse(file, options)
    rescue FasterCSV::MalformedCSVError
      nil
    end
  end

end

, , nil . :

# /models/csv_importer.rb

class CsvImporter
  include ActiveRecord::Validations

  validates_presence_of :file
  validate check_file_format
  attr_accessor csv_data

  def csv_data
    @csv_data ||= FasterCSV.safe_parse(file)
  end

...

  private

  def check_file_format
    errors.add :file, "Malformed CSV! Please check syntax" if csv_data.nil?
  end
end

, safe_parse, , , .

0

. /.

# /lib/fastercsv_is_valid.rb

class FasterCSV

  def self.is_valid?(file, options = {})
    begin
      FasterCSV.parse(file, options) { |row| }
      true
    rescue FasterCSV::MalformedCSV
      false
    end
  end

end

:

# /models/csv_importer.rb

class CsvImporter
  include ActiveRecord::Validations

  validates_presence_of :file
  validate check_file_format

...

  private

  def check_file_format
    errors.add :file, "Malformed CSV! Please check syntax" unless FasterCSV::is_valid? file
  end
end
+1

I assume that you want to analyze the CSV and do something with the analysis results. The worst case is that your CSV is valid and that you are parsing the file again. I would write something like this to cancel the result, so you only need to parse the CSV:

module FasterCSV

  def self.parse_and_validate(file, options = {})

    begin
      @parsed_result = FasterCSV.parse(file, options) { |row| }
    rescue FasterCSV::MalformedCSV
      @invalid = true
    end
  end

  def self.is_valid?
    !@invalid
  end    

  def self.parsed_result
    @parsed_result if self.valid?
  end

end

And then:

class CsvImporter
  include ActiveRecord::Validations

  validates_presence_of :file
  validate check_file_format

  # I assume you use the parsed result after the validations so in a before_save or something
  def do_your_parse_stuff
    here you would use FasterCSV::parsed_result
  end
...

  private

  def check_file_format
    FasterCSV::parse_and_validate(file)
    errors.add :file, "Malformed CSV! Please check syntax" unless FasterCSV::is_valid?
  end
end

In the above case, you can move the material to another class, which takes care of exchanging information with FasterCSV and eliminates the analysis result, because I do not think my example is thread safe :)

-1
source

All Articles