Commit 3ae7a3e8 by Marcin Urbanski

Tracking new attachment styles with a Rake task to refresh them

parent 74784558
......@@ -39,6 +39,7 @@ require 'paperclip/style'
require 'paperclip/attachment'
require 'paperclip/storage'
require 'paperclip/callback_compatibility'
require 'paperclip/missing_attachment_styles'
require 'paperclip/railtie'
require 'logger'
require 'cocaine'
......@@ -269,6 +270,7 @@ module Paperclip
end
attachment_definitions[name] = {:validations => []}.merge(options)
Paperclip.classes_with_attachments << self
after_save :save_attached_files
before_destroy :destroy_attached_files
......
require 'set'
module Paperclip
class << self
attr_accessor :classes_with_attachments
attr_writer :registered_attachments_styles_path
def registered_attachments_styles_path
@registered_attachments_styles_path ||= Rails.root.join('public/system/paperclip_attachments.yml').to_s
end
end
self.classes_with_attachments = Set.new
# Get list of styles saved on previous deploy (running rake paperclip:refresh:missing_styles)
def self.get_registered_attachments_styles
YAML.load_file(Paperclip.registered_attachments_styles_path)
rescue Errno::ENOENT
nil
end
private_class_method :get_registered_attachments_styles
def self.save_current_attachments_styles!
File.open(Paperclip.registered_attachments_styles_path, 'w') do |f|
YAML.dump(current_attachments_styles, f)
end
end
# Returns hash with styles for all classes using Paperclip.
# Unfortunately current version does not work with lambda styles:(
# {
# :User => {:avatar => [:small, :big]},
# :Book => {
# :cover => [:thumb, :croppable]},
# :sample => [:thumb, :big]},
# }
# }
def self.current_attachments_styles
Hash.new.tap do |current_styles|
Paperclip.classes_with_attachments.each do |klass|
klass.attachment_definitions.each do |attachment_name, attachment_attributes|
# TODO: is it even possible to take into account Procs?
next if attachment_attributes[:styles].kind_of?(Proc)
attachment_attributes[:styles].try(:keys).try(:each) do |style_name|
klass_sym = klass.to_s.to_sym
current_styles[klass_sym] ||= Hash.new
current_styles[klass_sym][attachment_name.to_sym] ||= Array.new
current_styles[klass_sym][attachment_name.to_sym] << style_name.to_sym
current_styles[klass_sym][attachment_name.to_sym].map!(&:to_s).sort!.map!(&:to_sym).uniq!
end
end
end
end
end
private_class_method :current_attachments_styles
# Returns hash with styles missing from recent run of rake paperclip:refresh:missing_styles
# {
# :User => {:avatar => [:big]},
# :Book => {
# :cover => [:croppable]},
# }
# }
def self.missing_attachments_styles
current_styles = current_attachments_styles
registered_styles = get_registered_attachments_styles
Hash.new.tap do |missing_styles|
current_styles.each do |klass, attachment_definitions|
attachment_definitions.each do |attachment_name, styles|
registered = registered_styles[klass][attachment_name] rescue []
missed = styles - registered
if missed.present?
klass_sym = klass.to_s.to_sym
missing_styles[klass_sym] ||= Hash.new
missing_styles[klass_sym][attachment_name.to_sym] ||= Array.new
missing_styles[klass_sym][attachment_name.to_sym].concat(missed.to_a)
missing_styles[klass_sym][attachment_name.to_sym].map!(&:to_s).sort!.map!(&:to_sym).uniq!
end
end
end
end
end
end
......@@ -60,6 +60,22 @@ namespace :paperclip do
end
end
end
desc "Regenerates missing thumbnail styles for all classes using Paperclip."
task :missing_styles => :environment do
# Force loading all model classes to never miss any has_attached_file declaration:
Dir[Rails.root + 'app/models/**/*.rb'].each { |path| load path }
Paperclip.missing_attachments_styles.each do |klass, attachment_definitions|
attachment_definitions.each do |attachment_name, missing_styles|
puts "Regenerating #{klass} -> #{attachment_name} -> #{missing_styles.inspect}"
ENV['CLASS'] = klass.to_s
ENV['ATTACHMENT'] = attachment_name.to_s
ENV['STYLES'] = missing_styles.join(',')
Rake::Task['paperclip:refresh:thumbnails'].execute
end
end
Paperclip.save_current_attachments_styles!
end
end
desc "Cleans out invalid attachments. Useful after you've added new validations."
......
......@@ -20,7 +20,7 @@ rescue LoadError => e
puts "debugger disabled"
end
ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
ROOT = Pathname(File.expand_path(File.join(File.dirname(__FILE__), '..')))
def silence_warnings
old_verbose, $VERBOSE = $VERBOSE, nil
......
require './test/helper'
class PaperclipMissingAttachmentStylesTest < Test::Unit::TestCase
context "Paperclip" do
setup do
Paperclip.classes_with_attachments = Set.new
end
teardown do
File.unlink(Paperclip.registered_attachments_styles_path) rescue nil
end
should "be able to keep list of models using it" do
assert_kind_of Set, Paperclip.classes_with_attachments
assert Paperclip.classes_with_attachments.empty?, 'list should be empty'
rebuild_model
assert_equal [Dummy].to_set, Paperclip.classes_with_attachments
end
should "enable to get and set path to registered styles file" do
assert_equal ROOT.join('public/system/paperclip_attachments.yml').to_s, Paperclip.registered_attachments_styles_path
Paperclip.registered_attachments_styles_path = '/tmp/config/paperclip_attachments.yml'
assert_equal '/tmp/config/paperclip_attachments.yml', Paperclip.registered_attachments_styles_path
Paperclip.registered_attachments_styles_path = nil
assert_equal ROOT.join('public/system/paperclip_attachments.yml').to_s, Paperclip.registered_attachments_styles_path
end
should "be able to get current attachment styles" do
assert_equal Hash.new, Paperclip.send(:current_attachments_styles)
rebuild_model :styles => {:croppable => '600x600>', :big => '1000x1000>'}
expected_hash = { :Dummy => {:avatar => [:big, :croppable]}}
assert_equal expected_hash, Paperclip.send(:current_attachments_styles)
end
should "be able to save current attachment styles for further comparison" do
rebuild_model :styles => {:croppable => '600x600>', :big => '1000x1000>'}
Paperclip.save_current_attachments_styles!
expected_hash = { :Dummy => {:avatar => [:big, :croppable]}}
assert_equal expected_hash, YAML.load_file(Paperclip.registered_attachments_styles_path)
end
should "be able to read registered attachment styles from file" do
rebuild_model :styles => {:croppable => '600x600>', :big => '1000x1000>'}
Paperclip.save_current_attachments_styles!
expected_hash = { :Dummy => {:avatar => [:big, :croppable]}}
assert_equal expected_hash, Paperclip.send(:get_registered_attachments_styles)
end
should "be able to calculate differences between registered styles and current styles" do
rebuild_model :styles => {:croppable => '600x600>', :big => '1000x1000>'}
Paperclip.save_current_attachments_styles!
rebuild_model :styles => {:thumb => 'x100', :export => 'x400>', :croppable => '600x600>', :big => '1000x1000>'}
expected_hash = { :Dummy => {:avatar => [:export, :thumb]} }
assert_equal expected_hash, Paperclip.missing_attachments_styles
ActiveRecord::Base.connection.create_table :books, :force => true
class ::Book < ActiveRecord::Base
has_attached_file :cover, :styles => {:small => 'x100', :large => '1000x1000>'}
has_attached_file :sample, :styles => {:thumb => 'x100'}
end
expected_hash = {
:Dummy => {:avatar => [:export, :thumb]},
:Book => {:sample => [:thumb], :cover => [:large, :small]}
}
assert_equal expected_hash, Paperclip.missing_attachments_styles
Paperclip.save_current_attachments_styles!
assert_equal Hash.new, Paperclip.missing_attachments_styles
end
# It's impossible to build styles hash without loading from database whole bunch of records
should "skip lambda-styles" do
rebuild_model :styles => lambda{ |attachment| attachment.instance.other == 'a' ? {:thumb => "50x50#"} : {:large => "400x400"} }
assert_equal Hash.new, Paperclip.send(:current_attachments_styles)
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment