2016-08-09 1 views
1

Nachdem ich die RailsCast beim Importieren von CSV (http://railscasts.com/episodes/396-importing-csv-and-excel) befolgt habe, versuche ich zu validieren, dass die hochgeladene Datei eine CSV-Datei ist.Ruby on Rails: CSV-Datei validieren

ich den Edelstein verwendet haben csv_validator so zu tun, als https://github.com/mattfordham/csv_validator

hier dokumentiert Und so sieht mein Modell wie folgt aus:

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 

Aber mein System erlaubt es mir immer noch nicht CSV importieren zu wählen Dateien (wie .xls), und ich erhalte den resultierenden Fehler: invalid byte sequence in UTF-8.

Kann mir bitte jemand sagen, warum und wie das zu lösen?

Bitte beachten Sie, dass ich Rails bin mit 4.2.6

+0

Sie können die Dateierweiterung überprüfen, bevor Sie versuchen, es zu importieren: 'file.path.split ('.'). Last.to_s.downcase == 'csv'' – MrYoshiji

+0

@MrYoshiji danke für Ihren Kommentar, den ich auch möchte um die Daten auch in bestimmten Spalten zu validieren, was dieses Juwel (sollte) mir erlauben, –

+0

dieses Juwel zu tun, können Sie die Daten in den Spalten abrufen, ist es Ihr Teil, um die Logik zu machen, "die Daten zu validieren" in der Säule. Ich kann eine Antwort posten, wenn Sie ein paar Tipps brauchen, wo Sie anfangen können. – MrYoshiji

Antwort

1

Sie eine neue Klasse erstellen, die ContactCsvRowValidator lassen sagen:

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 

Und es dann wie folgt verwenden:

# 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 

Dieses Muster kann leicht an Ihre Bedürfnisse angepasst werden. Wenn Sie beispielsweise mehrere verschiedene Modelle importieren müssen, können Sie einen Basis-CsvRowValidator erstellen, der grundlegende Methoden wie validate_fields, initialize und errors bereitstellt. Dann könnten Sie für jedes gewünschte Modell eine Klasse erstellen, die von diesem CsvRowValidator erbt und eigene Validierungen implementiert.