在导入CSV(http://railscasts.com/episodes/396-importing-csv-and-excel)后跟踪RailsCast,我正在尝试验证正在上传的文件是否为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 :(得分:3)
您可以创建一个新课程,比方说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_to_handle_invaid_row!(row)
return
end
# other logic
end
end
可以轻松修改此模式以满足您的需求。例如,如果您需要在多个不同模型上导入,则可以创建基本CsvRowValidator以提供基本方法,例如validate_fields
,initialize
和errors
。然后,您可以为所需的每个模型创建一个继承自此CsvRowValidator的类,并实现自己的验证。