Если вдруг захотелось изменить опцию :path в paperclip...
Позавчера столкнулся с проблемой, когда мне понадобилось изменить опцию :path в знаменитом и всеми используемом плагине для Rails paperclip от thoughtbot, когда проекту уже 2 месяца. Естественно, что файлов, за это время накопилось большое множество, и перемещать через консольные команды:
- не правильно вовсе, т.к. это почти что не возможно (структура, даже самая базовая настолько динамичная, что вряд ли это возможно без подключения, как минимум к базе данных… а bash + mysql – это hardcore);
- можно легко напутать, и переместить файлы в неправильное место;
- не люблю много писанины;
Лучше написать всеми любимый Raketask и радоваться, как он сделает всю работу за вас. И так, я начал с того, что полез в исходники paperclip. Так как я уже туда многократно заглядывал, то я знал, что там всё просто, логично, а не так как в attachment_fu. Решение нашлось через 2 часа.
Если вдруг у вас случилась такая же ситуация, вам понадобилось переместить файлы, и вы не знаете пока как, то предлагаю использовать ниже приведённый Raketask, который отработал на production и даже не разу не понадобилось восстанавливать файлы из backup’a.
Как пользоваться?
- если у вас нет Raketask’а для paperclip в lib/tasks/, то скопируйте его туда из gem’a
- дальше просто: подумайте какой path вы бы хотели использовать и напишите нечто вроде
- rake paperclip:change_path CLASS=Image PATH=:rails_root/public/system/:class/:attachment/:style/:id.:extension RAILS_ENV=production
- после этого сделайте commit и deploy на сервере с изменённым параметром :path для has_attachement
И это всё.
desc "Moves files to a new :path NB! backup your files before use this task (set CLASS and PATH, ATTACHMENT is optional)"
task :change_path => :environment do
raise 'PATH must be specified, like PATH=:rails_root/public/system/:class/:attachment/:style/:id.:extension' if ENV['PATH'].blank?
path = ENV['PATH']
for_all_attachments do |instance, name|
object = instance.send(name)
old_path = object.instance_variable_get :'@path'
styles = [:original] + object.styles.keys
styles.each do |style|
if object.exists?(style)
object.queued_for_write[style] = object.to_file(style)
end
end
object.instance_variable_set :'@path', path
object.flush_writes
object.instance_variable_set :'@path', old_path
object.instance_variable_set :'@queued_for_delete', styles.map { |style| object.path(style) }
object.flush_deletes
# if stopped working then use:
# path = Paperclip::Interpolations.interpolate(path, object, style)
# and own write and delete functions
end
end