Module: EncodedAttachment::ActiveResourceClassMethods

Defined in:
lib/activeresource/base.rb

Instance Method Summary collapse

Instance Method Details

#has_encoded_attachment(name) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/activeresource/base.rb', line 3

def has_encoded_attachment(name)
  schema do
    string    "#{name}_file_name", "#{name}_content_type"
    integer   "#{name}_file_size"
    attribute "#{name}_updated_at", "string"
    attribute name, "string"
  end
  
  define_method "#{name}_updated_at" do
    Time.parse(attributes["#{name}_updated_at"]) if attributes["#{name}_updated_at"].is_a?(String)
  end
  
  define_method "to_xml_with_encoded_#{name}" do |*args|
    # Normally, the file's XML is only included if the file has been changed in the resource
    # using file= or file_path= or file_url=
    # You can force file tag generation (i.e. even if the file has not changed) by using to_xml(:include_files => true)
    options, block = args
    
    options ||= {}
    options[:except] ||= []
    options[:except] = (options[:except] + [:"#{name}", :"#{name}_updated_at", :"#{name}_file_size"]).uniq
    options[:except] = (options[:except] + [:"#{name}_file_name", :"#{name}_content_type"]).uniq unless send("#{name}_changed?")
    options[:procs] ||= []
    
    options[:procs] << Proc.new { |options, record|
      file_options = { :type => 'file'}
      if send("#{name}_changed?") || options[:include_files] || (new_record? && !(send("#{name}").nil?))
        file_options.merge!   :name => send("#{name}_file_name"), :"content-type" => send("#{name}_content_type")
        options[:builder].tag!(name, file_options) { options[:builder].cdata! EncodedAttachment.encode_io(send(name)) }
      elsif send("#{name}_changed?") || options[:include_files]
        file_options.merge!     :nil => true
        options[:builder].tag!  name, "", file_options
      end
    }
    
    send "to_xml_without_encoded_#{name}", options, &block
  end
  alias_method_chain :to_xml, :"encoded_#{name}"
  
  define_method "load_with_attached_#{name}" do |attrs|
    attrs = attrs.stringify_keys
    if attrs.has_key?("#{name}")
      send "#{name}=", attrs.delete("#{name}"), @attributes.has_key?(name)
    elsif attrs.has_key?("#{name}_url")
      send "#{name}_url=", attrs.delete("#{name}_url"), @attributes.has_key?(name)
    end
    send "load_without_attached_#{name}", attrs
  end
  alias_method_chain :load, :"attached_#{name}"

  # Prevents someone from assigning the attachment attributes directly and skipping the handling methods
  define_method "attributes=" do |attrs|
    send :load, attrs
  end

  define_method "#{name}_changed=" do |bool|
    instance_variable_set("@#{name}_changed", bool)
  end
        
  define_method "#{name}_changed?" do
    instance_variable_get("@#{name}_changed") || false
  end
  
  define_method "#{name}_path=" do |file_path|
    send "#{name}=",              File.open(file_path)
    send "#{name}_file_name=",    File.basename(file_path)
    send "#{name}_content_type=", MIME::Types.type_for(File.basename(file_path)).first.content_type
  end
  
  define_method "#{name}_url=" do |*args|
    file_url, changed = args
    changed = (changed.nil? || changed) ? true : false
    if file_url
      url = URI.parse(file_url.to_s)
      content_type = MIME::Types.type_for(File.basename(url.path)).first.content_type
      
      io = StringIO.new(connection.get_attachment(url.path, 'Accept' => content_type))
      io.original_filename  = File.basename(url.path)
      io.content_type       = content_type
      
      send "#{name}=",  io, changed
    else
      send "#{name}=",  nil, changed
    end
  end
  
  define_method "#{name}=" do |*args|
    io, changed = args
    changed = (changed.nil? || changed) ? true : false
    attributes[name] = io
    if io.respond_to?(:original_filename)
      send "#{name}_file_name=",    io.original_filename
      send "#{name}_content_type=", MIME::Types.type_for(io.original_filename).first.content_type
    elsif io.nil?
      send "#{name}_file_name=",    nil
      send "#{name}_content_type=", nil
    end
    attributes.delete "#{name}_url"
    attributes.delete "#{name}_file_size"
    attributes.delete "#{name}_updated_at"
    send "#{name}_changed=", changed
  end
  
  define_method "save_#{name}_as" do |*args|
    raise "File not set - cannot be saved" if attributes[name].nil? || !(attributes[name].respond_to?(:read))
    path, overwrite = args
    overwrite = true if overwrite.nil?
    unless !(overwrite) && File.exist?(path)
      send(name).pos = 0
      File.open(path, 'w') { |f| f << send(name).read }
      return true
    else
      raise "File not saved - file already exists at #{path}"
    end
  end
end