从附件中提取并验证数据

时间:2015-02-19 21:15:48

标签: ruby-on-rails validation paperclip

我正在使用paperclip来管理我在rails中的文件上传。

从用户提供的附件中,我想提取一些数据以与附件所关联的模型相关联。

has_attached_file :resume, #...
# ...
def extract_resume_summary
  path_to_resume = self.resume.queued_for_write[:original].path
  extracted = parse_resume_file(path_to_resume)
  self.number_of_jobs = extracted.number_of_jobs
  self.highest_level_of_education = extracted.highest_level_of_education
rescue ResumeParseError => e
  @problem_with_resume = e.message
end

我在确定 时完全确定

我可以使用自定义Paperclip::Processor

class ::Paperclip::Summary < ::Paperclip::Processor
  def make
    @attachment.instance.extract_resume_summary
    Tempfile.new('unused')
  end
end
# ...
has_attached_file :resume, 
                  :styles => { :summary => {} }, 
                  :processors => [ :summary ] }, #...

但是合适并不是很好。我认为处理器旨在创建新文件(我不需要,因此是假的Tempfile)。

此外我的提取可能会失败,这意味着我的用户给了我错误的数据。我希望这是一个验证时间问题,因此我可以将其与其他验证错误一起报告,并且在验证后严格进行后处理。

我在初始化时尝试过攻击它:

validate :successfully_parses_resume

def successfully_parses_resume
  errors.add(:resume, @problem_with_resume) if @problem_with_resume
end

def initialize(attributes=nil, options={})
  super
  extract_resume_summary
end

但是我也不太确定这是正确的,因为这不仅是在文件上传时,而且在我稍后阅读模型时也是如此。如果我假设#resume=#[:resume]=自动更新提取的数据,则更不用说可能发生的混乱。

我认为在一个理想的世界中,我只是将Paperclip::Attachment子类化,并使我提取的数据同步为resume_file_nameresume_file_sizeresume_content_typeresume_created_at ,同时提取mime类型并计算文件大小。但是从源头来看,这些都是非常难以编码的。

还有另一种方法可以做到这一点,我忽略了吗?

1 个答案:

答案 0 :(得分:0)

我想出的解决方案是包装附件的制定者。这就是initialize期间所要求的,并且会让我有机会在验证前发现问题。

唯一的诀窍是,因为附件的setter是由has_attached_file创建的而不是从ActiveRecord::Base继承的,所以我不能只使用super,我需要明确引用由has_attached_file定义的版本(alias或我的偏好,instance_method):

has_attached_file :resume

old_setter = instance_method :resume=
define_method :resume= do |file|
  old_setter.bind(self).call(file)
  begin
    extracted = parse_resume_file(resume.path)
    self.number_of_jobs = extracted.number_of_jobs
    self.highest_level_of_education = extracted.highest_level_of_education
  rescue ResumeParseError => e
    @problem_with_resume = e.message
  end
end