lib/bulldog/has_attachment.rb in bulldog-0.1.0 vs lib/bulldog/has_attachment.rb in bulldog-0.1.1
- old
+ new
@@ -1,162 +1,182 @@
module Bulldog
module HasAttachment
- def self.included(base)
- base.extend ClassMethods
- base.instance_variable_set(:@attachment_reflections, {})
+ #
+ # Declare that this model has an attachment.
+ #
+ # TODO: example that shows all the options.
+ #
+ def has_attachment(name, &block)
+ unless include?(InstanceMethods)
+ extend ClassMethods
+ include InstanceMethods
+ end
- # We need to store the attachment changes ourselves, since
- # they're unavailable in an after_save.
- base.before_save :store_original_attachments
- base.after_save :save_attachments
- base.after_save :clear_original_attachments
+ reflection = attachment_reflections[name] || Reflection.new(self, name)
+ reflection.configure(&block)
+ attachment_reflections[name] = reflection
+ define_attachment_accessors(reflection.name)
+ define_attachment_attribute_methods(reflection.name)
+ end
- base.before_save :update_attachment_timestamps
- base.after_destroy :destroy_attachments
+ module InstanceMethods
+ def self.included(base)
+ base.instance_variable_set(:@attachment_reflections, {})
- # Force initialization of attachments, as #destroy will freeze
- # the attributes afterwards.
- base.before_destroy :initialize_remaining_attachments
+ # We need to store the attachment changes ourselves, since
+ # they're unavailable in an after_save.
+ base.before_save :store_original_attachments
+ base.after_save :save_attachments
+ base.after_save :clear_original_attachments
- %w[validation save create update].each do |event|
- base.send("before_#{event}", "process_attachments_for_before_#{event}")
- base.send("after_#{event}", "process_attachments_for_after_#{event}")
+ base.before_save :update_attachment_timestamps
+ base.after_destroy :destroy_attachments
+
+ # Force initialization of attachments, as #destroy will freeze
+ # the attributes afterwards.
+ base.before_destroy :initialize_remaining_attachments
+
+ %w[validation save create update].each do |event|
+ base.send("before_#{event}", "process_attachments_for_before_#{event}")
+ base.send("after_#{event}", "process_attachments_for_after_#{event}")
+ end
end
- end
- def save_attachments
- attachment_reflections.each do |name, reflection|
- original_attachment = @original_attachments[name] and
- original_attachment.destroy
- _attachment_for(name).save
+ def save_attachments
+ attachment_reflections.each do |name, reflection|
+ original_attachment = @original_attachments[name] and
+ original_attachment.destroy
+ _attachment_for(name).save
+ end
end
- end
- def destroy_attachments
- attachment_reflections.each do |name, reflection|
- _attachment_for(name).destroy
+ def destroy_attachments
+ attachment_reflections.each do |name, reflection|
+ _attachment_for(name).destroy
+ end
end
- end
- def update_attachment_timestamps
- attachment_reflections.each do |name, reflection|
- next unless send("#{name}_changed?")
- setter = "#{name}_updated_at="
- if respond_to?(setter)
- send(setter, Time.now)
+ def update_attachment_timestamps
+ attachment_reflections.each do |name, reflection|
+ next unless send("#{name}_changed?")
+ setter = "#{name}_updated_at="
+ if respond_to?(setter)
+ send(setter, Time.now)
+ end
end
end
- end
- def process_attachment(name, event, *args)
- reflection = attachment_reflections[name] or
- raise ArgumentError, "no such attachment: #{name}"
- _attachment_for(name).process(event, *args)
- end
+ def process_attachment(name, event, *args)
+ reflection = attachment_reflections[name] or
+ raise ArgumentError, "no such attachment: #{name}"
+ _attachment_for(name).process(event, *args)
+ end
- def attachment_reflection_for(name)
- self.class.attachment_reflections[name]
- end
+ def attachment_reflection_for(name)
+ self.class.attachment_reflections[name]
+ end
- private # -------------------------------------------------------
+ private # -------------------------------------------------------
- # Prefixed with '_', as it would collide with paperclip otherwise.
- def _attachment_for(name)
- read_attribute(name) or
- initialize_attachment(name)
- end
+ # Prefixed with '_', as it would collide with paperclip otherwise.
+ def _attachment_for(name)
+ read_attribute(name) or
+ initialize_attachment(name)
+ end
- def initialize_attachment(name)
- if new_record?
- value = nil
- else
- reflection = attachment_reflection_for(name)
- file_name_column = reflection.column_name_for_stored_attribute(:file_name)
- file_name = file_name_column ? send(file_name_column) : nil
- if file_name_column && file_name.nil?
+ def initialize_attachment(name)
+ if new_record?
value = nil
else
- template = reflection.path_template
- style = reflection.styles[:original]
- original_path = Interpolation.interpolate(template, self, name, style, :basename => file_name)
- if File.exist?(original_path)
- value = SavedFile.new(original_path, :file_name => file_name)
+ reflection = attachment_reflection_for(name)
+ file_name_column = reflection.column_name_for_stored_attribute(:file_name)
+ file_name = file_name_column ? send(file_name_column) : nil
+ if file_name_column && file_name.nil?
+ value = nil
else
- if file_name_column
- value = MissingFile.new(:file_name => file_name)
+ template = reflection.path_template
+ style = reflection.styles[:original]
+ original_path = Interpolation.interpolate(template, self, name, style, :basename => file_name)
+ if File.exist?(original_path)
+ value = SavedFile.new(original_path, :file_name => file_name)
else
- value = nil
+ if file_name_column
+ value = MissingFile.new(:file_name => file_name)
+ else
+ value = nil
+ end
end
end
end
+
+ attachment = make_attachment_for(name, value)
+ write_attribute_without_dirty(name, attachment)
+ attachment.read_storable_attributes
+ attachment
end
- attachment = make_attachment_for(name, value)
- write_attribute_without_dirty(name, attachment)
- attachment.read_storable_attributes
- attachment
- end
+ def assign_attachment(name, value)
+ old_attachment = _attachment_for(name)
+ unless old_attachment.value == value
+ old_attachment.unload
+ new_attachment = make_attachment_for(name, value)
+ new_attachment.load
+ write_attribute(name, new_attachment)
+ end
+ end
- def assign_attachment(name, value)
- old_attachment = _attachment_for(name)
- unless old_attachment.value == value
- old_attachment.unload
- new_attachment = make_attachment_for(name, value)
- new_attachment.load
- write_attribute(name, new_attachment)
+ def make_attachment_for(name, value)
+ return Attachment.none(self, name) if value.nil?
+ stream = Stream.new(value)
+ reflection = attachment_reflection_for(name)
+ type = reflection.detect_attachment_type(self, stream)
+ Attachment.of_type(type, self, name, stream)
end
- end
- def make_attachment_for(name, value)
- return Attachment.none(self, name) if value.nil?
- stream = Stream.new(value)
- reflection = attachment_reflection_for(name)
- type = reflection.detect_attachment_type(self, stream)
- Attachment.of_type(type, self, name, stream)
- end
+ def store_original_attachments
+ @original_attachments = {}
+ attachment_reflections.each do |name, reflection|
+ if send("#{name}_changed?")
+ @original_attachments[name] = send("#{name}_was")
+ end
+ end
+ end
- def store_original_attachments
- @original_attachments = {}
- attachment_reflections.each do |name, reflection|
- if send("#{name}_changed?")
- @original_attachments[name] = send("#{name}_was")
+ def clear_original_attachments
+ # This can be unset if the record is resaved between store and
+ # clear (e.g., in an after_save: store, save, store, clear, clear).
+ if instance_variable_defined?(:@original_attachments)
+ remove_instance_variable :@original_attachments
end
end
- end
- def clear_original_attachments
- # Somehow this can be unset sometimes. TODO: Work out how.
- if instance_variable_defined?(:@original_attachments)
- remove_instance_variable :@original_attachments
+ def process_attachments_for_event(event, *args)
+ self.class.attachment_reflections.each do |name, reflection|
+ _attachment_for(reflection.name).process(event, *args)
+ end
end
- end
- def process_attachments_for_event(event, *args)
- self.class.attachment_reflections.each do |name, reflection|
- _attachment_for(reflection.name).process(event, *args)
+ def initialize_remaining_attachments
+ self.attachment_reflections.each do |name, reflection|
+ _attachment_for(name) # force initialization
+ end
end
- end
- def initialize_remaining_attachments
- self.attachment_reflections.each do |name, reflection|
- _attachment_for(name) # force initialization
+ %w[validation save create update].each do |event|
+ module_eval <<-EOS
+ def process_attachments_for_before_#{event}
+ process_attachments_for_event(:before_#{event})
+ end
+ def process_attachments_for_after_#{event}
+ process_attachments_for_event(:after_#{event})
+ end
+ EOS
end
- end
- %w[validation save create update].each do |event|
- module_eval <<-EOS
- def process_attachments_for_before_#{event}
- process_attachments_for_event(:before_#{event})
- end
- def process_attachments_for_after_#{event}
- process_attachments_for_event(:after_#{event})
- end
- EOS
+ delegate :attachment_reflections, :to => 'self.class'
end
- delegate :attachment_reflections, :to => 'self.class'
-
module ClassMethods
def attachment_reflections
@attachment_reflections ||=
begin
hash = {}
@@ -164,22 +184,9 @@
superhash.map do |name, reflection|
hash[name] = reflection.clone
end
hash
end
- end
-
- #
- # Declare that this model has an attachment.
- #
- # TODO: example that shows all the options.
- #
- def has_attachment(name, &block)
- reflection = attachment_reflections[name] || Reflection.new(self, name)
- reflection.configure(&block)
- attachment_reflections[name] = reflection
- define_attachment_accessors(reflection.name)
- define_attachment_attribute_methods(reflection.name)
end
def define_attachment_accessors(name)
module_eval <<-EOS, __FILE__, __LINE__
def #{name}