2016-08-09 2 views
1

После выполнения RailsCast при импорте CSV (http://railscasts.com/episodes/396-importing-csv-and-excel), я пытаюсь проверить, что загружаемый файл является CSV-файлом.Ruby on Rails: проверить файл CSV

Я использовал камень csv_validator сделать так, как описано здесь https://github.com/mattfordham/csv_validator

И поэтому моя модель выглядит следующим образом:

class Contact < ActiveRecord::Base 
    belongs_to :user 

    attr_accessor :my_csv_file 
    validates :my_csv_file, :csv => true 

    def self.to_csv(options = {}) 
    CSV.generate(options) do |csv| 
     csv << column_names 
     all.each do |contact| 
      csv << contact.attributes.values_at(*column_names) 
     end 
    end 
    end 
    def self.import(file, user) 
    allowed_attributes = ["firstname","surname","email","user_id","created_at","updated_at", "title"] 
    CSV.foreach(file.path, headers: true) do |row| 
     contact = find_by_email_and_user_id(row["email"], user) || new 
     contact.user_id = user 
     contact.attributes = row.to_hash.select { |k,v| allowed_attributes.include? k } 
     contact.save! 
    end 
    end 
end 

Но моя система по-прежнему позволяет мне выбрать, чтобы импортировать не-CSV файлы (например, .xls), и я получаю результирующую ошибку: invalid byte sequence in UTF-8.

Может кто-нибудь, пожалуйста, скажите мне, почему и как это решить?

Пожалуйста, обратите внимание, что я использую Rails 4.2.6

+0

Вы можете проверить расширение файла, прежде чем пытаться его импортировать: 'file.path.split ('.'). Last.to_s.downcase == 'csv'' – MrYoshiji

+0

@MrYoshiji спасибо за ваш комментарий, я бы тоже хотел для проверки данных в определенных столбцах, хотя, что этот камень (должен) позволить мне сделать –

+0

этот драгоценный камень позволяет вам извлекать данные в столбцах, это ваша роль, чтобы заставить логику «проверять данные» в колонка. Я могу опубликовать ответ, если вы хотите узнать, с чего начать. – MrYoshiji

ответ

1

Вы можете создать новый класс, скажем ContactCsvRowValidator:

class ContactCsvRowValidator 

    def initialize(row) 
    @row = row.with_indifferent_access # allows you to use either row[:a] and row['a'] 
    @errors = [] 
    end 

    def validate_fields 
    if @row['firstname'].blank? 
     @errors << 'Firstname cannot be empty' 
    end 

    # etc. 
    end 

    def errors 
    @errors.join('. ') 
    end 
end 

И затем использовать его как это:

# contact.rb 
def self.import(file, user) 
    allowed_attributes = ["firstname","surname","email","user_id","created_at","updated_at", "title"] 
    if file.path.split('.').last.to_s.downcase != 'csv' 
    some_method_which_handle_the_fact_the_file_is_not_csv! 
    end 
    CSV.foreach(file.path, headers: true) do |row| 
    row_validator = ContactCsvRowValidator.new(row) 
    errors = row_validator.errors 
    if errors.present? 
     some_method_which_handle_the_fact_this_row_is_not_valid!(row) 
     return 
    end 

    # other logic 
    end 
end 

Этот шаблон можно легко изменить в соответствии с вашими потребностями. Например, если вам нужно импортировать несколько разных моделей, вы можете создать базовый CsvRowValidator, который предоставляет базовые методы, такие как validate_fields, initialize и errors. Затем вы можете создать класс, наследующий от этого CsvRowValidator для каждой желаемой модели, имея свои собственные проверки.