我正在使用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_name
,resume_file_size
,resume_content_type
,resume_created_at
,同时提取mime类型并计算文件大小。但是从源头来看,这些都是非常难以编码的。
还有另一种方法可以做到这一点,我忽略了吗?
答案 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