magic-paperclip 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.markdown +74 -0
- data/Rakefile +10 -0
- data/lib/magic-paperclip.rb +48 -0
- data/lib/magic-paperclip/railtie.rb +12 -0
- data/lib/magic-paperclip/version.rb +3 -0
- data/magic-paperlcip.gemspec +28 -0
- data/test/content_type_test.rb +39 -0
- data/test/database.yml +3 -0
- data/test/fixtures/zip_file_called.txt +0 -0
- data/test/helper.rb +42 -0
- metadata +125 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# MagicPaperclip
|
2
|
+
|
3
|
+
[Paperclip] is a wonderful module by Thoughtbot that lets makes handling
|
4
|
+
attachments in Rails a breeze, except for one minor niggle - file types. It
|
5
|
+
relies on the content type header sent by the browser which is woefully
|
6
|
+
inconsistent. For example, when uploading a zip the possible values sent
|
7
|
+
for content type are:
|
8
|
+
|
9
|
+
+ '`application/octet-stream`'
|
10
|
+
+ '`application/x-zip-compressed`'
|
11
|
+
+ '`application/zip`'
|
12
|
+
+ '' (yes empty)
|
13
|
+
|
14
|
+
In short you can't rely on Content-Type from the browser to ever have a
|
15
|
+
sensible value.
|
16
|
+
|
17
|
+
Thus the purpose of this module: it uses the wonderful
|
18
|
+
[libmagic](http://www.darwinsys.com/file/) to work out the file type based
|
19
|
+
on the contents of the uploaded file without shelling out to `file` to do its
|
20
|
+
work.
|
21
|
+
|
22
|
+
# Requirements
|
23
|
+
|
24
|
+
The ruby-filemagic gem (which this gem uses) depends upon `libmagic` must be
|
25
|
+
installed to give us file type detection. On Linux this means installing the
|
26
|
+
relevant package:
|
27
|
+
|
28
|
+
sudo apt-get install libmagic-dev # Deb
|
29
|
+
sudo yum install file-devel # rpm
|
30
|
+
sudo emerge file # gentoo
|
31
|
+
|
32
|
+
On OSX ships with the `file` binary but not the `libmagic` shared library so I
|
33
|
+
recommend installing it via [homebrew]:
|
34
|
+
|
35
|
+
brew install libmagic
|
36
|
+
# Since this will be in a non-standard place we need to build ruby-filemagic specially
|
37
|
+
gem install ruby-filemagic -- --with-opt-dir=$(brew list libmagic | head -n1 | xargs dirname)
|
38
|
+
|
39
|
+
# Installation
|
40
|
+
|
41
|
+
Include the gem in your Gemfile:
|
42
|
+
|
43
|
+
gem 'magic-paperclip'
|
44
|
+
|
45
|
+
# Usage
|
46
|
+
|
47
|
+
Its all automatic - magic-paperclip does its trick by just being in the
|
48
|
+
Gemfile (via a Railtie).
|
49
|
+
|
50
|
+
When a Paperclip attachment is assigned to its content_type will be detected
|
51
|
+
and will overwrite what the browser sends.
|
52
|
+
|
53
|
+
# Caveats/Bugs
|
54
|
+
|
55
|
+
libmagic often returns charset info or similar for files (i.e. `text/plain;
|
56
|
+
charset=us-asci`) that this module attempts to remove to use just the base
|
57
|
+
type. Supposedly older versions of libmagic might return this in a
|
58
|
+
different format and thus not get removed. If you find an example of this
|
59
|
+
happening please let me know.
|
60
|
+
|
61
|
+
# Credits & License
|
62
|
+
|
63
|
+

|
64
|
+
|
65
|
+
This gem was developed for use at [DigiResults] and pulled out into a reusable gem.
|
66
|
+
|
67
|
+
Released under the [MIT License][MIT]
|
68
|
+
|
69
|
+
Copyright (c) 2011, Ash Berlin and DigiResults Ltd.
|
70
|
+
|
71
|
+
[Paperclip]: http://github.com/thoughtbot/paperclip
|
72
|
+
[homebrew]: http://mxcl.github.com/homebrew/
|
73
|
+
[MIT]: http://creativecommons.org/licenses/MIT/
|
74
|
+
[DigiResults]: http://www.digiresults.com/
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Released under MIT License
|
2
|
+
# Copyright (c) 2011 Ash Berlin and DigiResults Ltd.
|
3
|
+
|
4
|
+
require 'filemagic'
|
5
|
+
require 'paperclip'
|
6
|
+
|
7
|
+
require 'magic-paperclip/railtie'
|
8
|
+
|
9
|
+
module Paperclip
|
10
|
+
def self.magic_content_type!
|
11
|
+
Attachment.send :include, MagicPaperclip
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module MagicPaperclip
|
16
|
+
def self.included( base )
|
17
|
+
base.class_eval do
|
18
|
+
alias_method :assign_without_filemagic, :assign
|
19
|
+
alias_method :assign, :assign_with_filemagic
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def assign_with_filemagic( uploaded_file )
|
24
|
+
# Call next method up the chain
|
25
|
+
val = assign_without_filemagic( uploaded_file )
|
26
|
+
|
27
|
+
return val if uploaded_file.is_a?( Paperclip::Attachment )
|
28
|
+
|
29
|
+
if uploaded_file
|
30
|
+
magic = FileMagic.new( FileMagic::MAGIC_MIME )
|
31
|
+
|
32
|
+
if defined?( StringIO ) && uploaded_file.is_a?( StringIO )
|
33
|
+
type = magic.buffer( uploaded_file.string )
|
34
|
+
else
|
35
|
+
type = magic.file( uploaded_file.path )
|
36
|
+
end
|
37
|
+
|
38
|
+
# Remove the '; charset=us-ascii' from the end if there is one
|
39
|
+
type.sub! /\s*;.*$/, ''
|
40
|
+
|
41
|
+
instance_write( :content_type, type )
|
42
|
+
end
|
43
|
+
val
|
44
|
+
ensure
|
45
|
+
magic.close if magic
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "magic-paperclip/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "magic-paperclip"
|
7
|
+
s.version = MagicPaperclip::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ash Berlin"]
|
10
|
+
s.email = ["ash.berlin@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/DigiResults/magic-paperclip"
|
12
|
+
s.summary = %q{Filemagic based mimetype detection for Paperclip}
|
13
|
+
s.description = %q{Adds better (a.k.a magic) file type detection support into Thoughtbot's Paperclip}
|
14
|
+
|
15
|
+
#s.rubyforge_project = "paperclip-filemagic"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency 'ruby-filemagic'
|
23
|
+
s.add_dependency 'paperclip'
|
24
|
+
|
25
|
+
s.add_development_dependency 'mocha'
|
26
|
+
s.add_development_dependency 'shoulda'
|
27
|
+
s.add_development_dependency 'sqlite3-ruby'
|
28
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class ContentTypeTest < Test::Unit::TestCase
|
4
|
+
context "Assigning a StringIO attachment" do
|
5
|
+
setup do
|
6
|
+
rebuild_model
|
7
|
+
@file = StringIO.new("abc")
|
8
|
+
@file.stubs(:original_filename).returns("5k.png\n\n")
|
9
|
+
@file.stubs(:content_type).returns("image/png\n\n")
|
10
|
+
@file.stubs(:to_tempfile).returns(@file)
|
11
|
+
@dummy = Dummy.new
|
12
|
+
@dummy.avatar = @file
|
13
|
+
end
|
14
|
+
|
15
|
+
should "set content_type based on file magic" do
|
16
|
+
assert_equal "text/plain", @dummy.avatar.content_type
|
17
|
+
assert_equal "text/plain", @dummy.avatar_content_type
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "Assigning a ZIP upfile attachment" do
|
22
|
+
setup do
|
23
|
+
rebuild_model
|
24
|
+
@file = File.new File.join( FIXTURES_DIR, 'zip_file_called.txt' )
|
25
|
+
class << @file
|
26
|
+
include Paperclip::Upfile
|
27
|
+
end
|
28
|
+
|
29
|
+
@file.stubs(:content_type).returns("") # Some versions of chrome do this
|
30
|
+
@dummy = Dummy.new
|
31
|
+
@dummy.avatar = @file
|
32
|
+
end
|
33
|
+
|
34
|
+
should "set content_type based on file magic" do
|
35
|
+
assert_equal "application/zip", @dummy.avatar.content_type
|
36
|
+
assert_equal "application/zip", @dummy.avatar_content_type
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/test/database.yml
ADDED
Binary file
|
data/test/helper.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Copied from Paperclip's own test suite
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
require 'mocha'
|
5
|
+
require 'shoulda'
|
6
|
+
require 'test/unit'
|
7
|
+
|
8
|
+
require 'magic-paperclip'
|
9
|
+
|
10
|
+
Paperclip.magic_content_type!
|
11
|
+
|
12
|
+
FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
|
13
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
14
|
+
ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(File.dirname(__FILE__) + "/debug.log")
|
15
|
+
ActiveRecord::Base.establish_connection(config['test'])
|
16
|
+
|
17
|
+
|
18
|
+
class Dummy
|
19
|
+
end
|
20
|
+
|
21
|
+
def rebuild_model options = {}
|
22
|
+
ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
|
23
|
+
table.column :other, :string
|
24
|
+
table.column :avatar_file_name, :string
|
25
|
+
table.column :avatar_content_type, :string
|
26
|
+
table.column :avatar_file_size, :integer
|
27
|
+
table.column :avatar_updated_at, :datetime
|
28
|
+
table.column :avatar_fingerprint, :string
|
29
|
+
end
|
30
|
+
rebuild_class options
|
31
|
+
end
|
32
|
+
|
33
|
+
def rebuild_class options = {}
|
34
|
+
ActiveRecord::Base.send(:include, Paperclip::Glue)
|
35
|
+
Object.send(:remove_const, "Dummy") rescue nil
|
36
|
+
Object.const_set("Dummy", Class.new(ActiveRecord::Base))
|
37
|
+
Dummy.class_eval do
|
38
|
+
include Paperclip::Glue
|
39
|
+
has_attached_file :avatar, options
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: magic-paperclip
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ash Berlin
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-08-01 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: ruby-filemagic
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: paperclip
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0"
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: mocha
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: shoulda
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: sqlite3-ruby
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
type: :development
|
70
|
+
version_requirements: *id005
|
71
|
+
description: Adds better (a.k.a magic) file type detection support into Thoughtbot's Paperclip
|
72
|
+
email:
|
73
|
+
- ash.berlin@gmail.com
|
74
|
+
executables: []
|
75
|
+
|
76
|
+
extensions: []
|
77
|
+
|
78
|
+
extra_rdoc_files: []
|
79
|
+
|
80
|
+
files:
|
81
|
+
- .gitignore
|
82
|
+
- Gemfile
|
83
|
+
- README.markdown
|
84
|
+
- Rakefile
|
85
|
+
- lib/magic-paperclip.rb
|
86
|
+
- lib/magic-paperclip/railtie.rb
|
87
|
+
- lib/magic-paperclip/version.rb
|
88
|
+
- magic-paperlcip.gemspec
|
89
|
+
- test/content_type_test.rb
|
90
|
+
- test/database.yml
|
91
|
+
- test/fixtures/zip_file_called.txt
|
92
|
+
- test/helper.rb
|
93
|
+
has_rdoc: true
|
94
|
+
homepage: https://github.com/DigiResults/magic-paperclip
|
95
|
+
licenses: []
|
96
|
+
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: "0"
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: "0"
|
114
|
+
requirements: []
|
115
|
+
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 1.6.1
|
118
|
+
signing_key:
|
119
|
+
specification_version: 3
|
120
|
+
summary: Filemagic based mimetype detection for Paperclip
|
121
|
+
test_files:
|
122
|
+
- test/content_type_test.rb
|
123
|
+
- test/database.yml
|
124
|
+
- test/fixtures/zip_file_called.txt
|
125
|
+
- test/helper.rb
|