Ben*_*ith 1 ruby csv excel ruby-on-rails ruby-on-rails-4
在导入 CSV 时遵循 RailsCast ( http://railscasts.com/episodes/396-importing-csv-and-excel ),我正在尝试验证正在上传的文件是否为 CSV 文件。
我已经使用 gemcsv_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
Run Code Online (Sandbox Code Playgroud)
但是我的系统仍然允许我选择导入非 CSV 文件(例如 .xls),并且我收到了由此产生的错误:invalid byte sequence in UTF-8.
有人可以告诉我为什么以及如何解决这个问题吗?
请注意,我使用的是 Rails 4.2.6
您可以创建一个新类,例如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
Run Code Online (Sandbox Code Playgroud)
然后像这样使用它:
# 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
Run Code Online (Sandbox Code Playgroud)
可以轻松修改此模式以满足您的需要。例如,如果您需要对多个不同的模型进行导入,您可以创建一个基本的 CsvRowValidator 来提供基本的方法,例如validate_fields、initialize和errors。然后,您可以为您想要的每个模型创建一个从该 CsvRowValidator 继承的类,并实现其自己的验证。