paperclip-storage-ftp 1.0.0.rc3 → 1.0.0
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/README.md +52 -33
- data/lib/paperclip/storage/ftp/server.rb +17 -4
- data/paperclip-storage-ftp.gemspec +1 -1
- data/spec/paperclip/storage/ftp/server_spec.rb +72 -15
- metadata +5 -8
data/README.md
CHANGED
@@ -9,9 +9,11 @@ to be stored on FTP servers.
|
|
9
9
|
|
10
10
|
## Installation
|
11
11
|
|
12
|
-
Add this line to your application's Gemfile
|
12
|
+
Add this line to your application's `Gemfile`:
|
13
13
|
|
14
|
-
|
14
|
+
```ruby
|
15
|
+
gem "paperclip-storage-ftp"
|
16
|
+
```
|
15
17
|
|
16
18
|
And then execute:
|
17
19
|
|
@@ -25,40 +27,45 @@ Or install it yourself as:
|
|
25
27
|
|
26
28
|
Somewhere in your code:
|
27
29
|
|
28
|
-
|
30
|
+
```ruby
|
31
|
+
require "paperclip/storage/ftp"
|
32
|
+
```
|
29
33
|
|
30
34
|
In your model:
|
31
35
|
|
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
|
-
|
36
|
+
```ruby
|
37
|
+
class User < ActiveRecord::Base
|
38
|
+
has_attached_file :avatar,
|
39
|
+
|
40
|
+
# Choose the FTP storage backend
|
41
|
+
:storage => :ftp,
|
42
|
+
|
43
|
+
# Set where to store the file on the FTP server(s).
|
44
|
+
# This supports Paperclip::Interpolations.
|
45
|
+
:path => "/path_on_ftp_server/:attachment/:id/:style/:filename",
|
46
|
+
|
47
|
+
# The full URL of where the attachment is publicly accessible.
|
48
|
+
# This supports Paperclip::Interpolations.
|
49
|
+
:url => "/url_prefix/:attachment/:id/:style/:filename",
|
50
|
+
|
51
|
+
# The list of FTP servers to use
|
52
|
+
:ftp_servers => [
|
53
|
+
{
|
54
|
+
:host => "ftp1.example.com",
|
55
|
+
:user => "foo",
|
56
|
+
:password => "bar",
|
57
|
+
:port => 21, # optional
|
58
|
+
},
|
59
|
+
# Add more servers if needed
|
60
|
+
{
|
61
|
+
:host => "ftp2.example.com",
|
62
|
+
:user => "foo",
|
63
|
+
:password => "bar",
|
64
|
+
:port => 2121
|
65
|
+
}
|
66
|
+
]
|
67
|
+
end
|
68
|
+
```
|
62
69
|
|
63
70
|
## Contributing
|
64
71
|
|
@@ -67,3 +74,15 @@ In your model:
|
|
67
74
|
3. Commit your changes (`git commit -am 'Added some feature'`)
|
68
75
|
4. Push to the branch (`git push origin my-new-feature`)
|
69
76
|
5. Create new Pull Request
|
77
|
+
|
78
|
+
## Authors
|
79
|
+
|
80
|
+
* [Sebastian Röbke](https://github.com/boosty)
|
81
|
+
* and other friendly [contributors](https://github.com/xing/paperclip-storage-ftp/graphs/contributors)
|
82
|
+
|
83
|
+
You can find out more about our work on our [dev blog](http://devblog.xing.com).
|
84
|
+
|
85
|
+
Copyright (c) 2012 [XING AG](http://www.xing.com)
|
86
|
+
|
87
|
+
Released under the MIT license. For full details see [LICENSE](https://github.com/xing/paperclip-storage-ftp/blob/master/LICENSE)
|
88
|
+
included in this distribution.
|
@@ -6,8 +6,14 @@ module Paperclip
|
|
6
6
|
module Ftp
|
7
7
|
class Server
|
8
8
|
|
9
|
+
@@connections = {}
|
10
|
+
|
11
|
+
def self.clear_connections
|
12
|
+
@@connections.clear
|
13
|
+
end
|
14
|
+
|
9
15
|
attr_accessor :host, :user, :password
|
10
|
-
attr_writer :
|
16
|
+
attr_writer :port
|
11
17
|
|
12
18
|
def initialize(options = {})
|
13
19
|
options.each do |k,v|
|
@@ -35,12 +41,19 @@ module Paperclip
|
|
35
41
|
end
|
36
42
|
|
37
43
|
def connection
|
38
|
-
|
39
|
-
|
44
|
+
connection = @@connections["#{host}:#{port}"] ||= build_connection
|
45
|
+
if connection.closed?
|
40
46
|
connection.connect(host, port)
|
41
47
|
connection.login(user, password)
|
42
|
-
connection
|
43
48
|
end
|
49
|
+
connection
|
50
|
+
end
|
51
|
+
|
52
|
+
def build_connection
|
53
|
+
connection = Net::FTP.new
|
54
|
+
connection.connect(host, port)
|
55
|
+
connection.login(user, password)
|
56
|
+
connection
|
44
57
|
end
|
45
58
|
|
46
59
|
def port
|
@@ -11,7 +11,7 @@ Gem::Specification.new do |gem|
|
|
11
11
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
12
12
|
gem.name = "paperclip-storage-ftp"
|
13
13
|
gem.require_paths = ["lib"]
|
14
|
-
gem.version = "1.0.0
|
14
|
+
gem.version = "1.0.0"
|
15
15
|
|
16
16
|
gem.add_dependency("paperclip")
|
17
17
|
|
@@ -1,6 +1,10 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Paperclip::Storage::Ftp::Server do
|
4
|
+
before(:each) do
|
5
|
+
Paperclip::Storage::Ftp::Server.clear_connections
|
6
|
+
end
|
7
|
+
|
4
8
|
let(:server) { Paperclip::Storage::Ftp::Server.new }
|
5
9
|
|
6
10
|
context "initialize" do
|
@@ -25,36 +29,43 @@ describe Paperclip::Storage::Ftp::Server do
|
|
25
29
|
end
|
26
30
|
|
27
31
|
context "#file_exists?" do
|
32
|
+
before do
|
33
|
+
server.stub(:connection).and_return(double("connection"))
|
34
|
+
end
|
35
|
+
|
28
36
|
it "returns true if the file exists on the server" do
|
29
|
-
server.connection = double("connection")
|
30
37
|
server.connection.should_receive(:nlst).with("/files/original").and_return(["foo.jpg"])
|
31
38
|
server.file_exists?("/files/original/foo.jpg").should be_true
|
32
39
|
end
|
33
40
|
|
34
41
|
it "recognizes complete file paths correctly" do
|
35
|
-
server.connection = double("connection")
|
36
42
|
server.connection.should_receive(:nlst).with("/files/original").and_return(["/files/original/foo.jpg"])
|
37
43
|
server.file_exists?("/files/original/foo.jpg").should be_true
|
38
44
|
end
|
39
45
|
|
40
46
|
it "returns false if the file does not exist on the server" do
|
41
|
-
server.connection = double("connection")
|
42
47
|
server.connection.should_receive(:nlst).with("/files/original").and_return([])
|
43
48
|
server.file_exists?("/files/original/foo.jpg").should be_false
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
47
52
|
context "#get_file" do
|
53
|
+
before do
|
54
|
+
server.stub(:connection).and_return(double("connection"))
|
55
|
+
end
|
56
|
+
|
48
57
|
it "returns the file object" do
|
49
|
-
server.connection = double("connection")
|
50
58
|
server.connection.should_receive(:getbinaryfile).with("/files/original.jpg", "/tmp/original.jpg")
|
51
59
|
server.get_file("/files/original.jpg", "/tmp/original.jpg")
|
52
60
|
end
|
53
61
|
end
|
54
62
|
|
55
63
|
context "#put_file" do
|
64
|
+
before do
|
65
|
+
server.stub(:connection).and_return(double("connection"))
|
66
|
+
end
|
67
|
+
|
56
68
|
it "stores the file on the server" do
|
57
|
-
server.connection = double("connection")
|
58
69
|
server.should_receive(:mkdir_p).with("/files")
|
59
70
|
server.connection.should_receive(:putbinaryfile).with("/tmp/original.jpg", "/files/original.jpg")
|
60
71
|
server.put_file("/tmp/original.jpg", "/files/original.jpg")
|
@@ -62,31 +73,78 @@ describe Paperclip::Storage::Ftp::Server do
|
|
62
73
|
end
|
63
74
|
|
64
75
|
context "#delete_file" do
|
76
|
+
before do
|
77
|
+
server.stub(:connection).and_return(double("connection"))
|
78
|
+
end
|
79
|
+
|
65
80
|
it "deletes the file on the server" do
|
66
|
-
server.connection = double("connection")
|
67
81
|
server.connection.should_receive(:delete).with("/files/original.jpg")
|
68
82
|
server.delete_file("/files/original.jpg")
|
69
83
|
end
|
70
84
|
end
|
71
85
|
|
72
|
-
context "#
|
73
|
-
it "returns
|
86
|
+
context "#build_connection" do
|
87
|
+
it "returns the ftp connection for the given server" do
|
74
88
|
server.host = "ftp.example.com"
|
75
89
|
server.user = "user"
|
76
90
|
server.password = "password"
|
77
91
|
|
78
|
-
|
79
|
-
Net::FTP.should_receive(:new).
|
80
|
-
|
81
|
-
|
92
|
+
ftp = double("ftp")
|
93
|
+
Net::FTP.should_receive(:new).and_return(ftp)
|
94
|
+
ftp.should_receive(:connect).with(server.host, server.port)
|
95
|
+
ftp.should_receive(:login).with(server.user, server.password)
|
96
|
+
server.build_connection.should == ftp
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "#connection" do
|
101
|
+
it "returns the memoized ftp connection for the given server" do
|
102
|
+
connection = double("connection", :closed? => false)
|
103
|
+
server.should_receive(:build_connection).once.and_return(connection)
|
104
|
+
server.connection.should == connection
|
105
|
+
|
106
|
+
# same host, same port => memoize
|
107
|
+
same_server = Paperclip::Storage::Ftp::Server.new(
|
108
|
+
:host => server.host,
|
109
|
+
:port => server.port
|
110
|
+
)
|
111
|
+
same_server.should_receive(:build_connection).never
|
112
|
+
same_server.connection.should == connection
|
82
113
|
|
83
|
-
|
114
|
+
# different host => do not memoize
|
115
|
+
other_host_connection = double("other_host_connection", :closed? => false)
|
116
|
+
other_host_server = Paperclip::Storage::Ftp::Server.new(
|
117
|
+
:host => "other.#{server.host}",
|
118
|
+
:port => server.port
|
119
|
+
)
|
120
|
+
other_host_server.should_receive(:build_connection).once.and_return(other_host_connection)
|
121
|
+
other_host_server.connection.should == other_host_connection
|
122
|
+
|
123
|
+
# different port => do not memoize
|
124
|
+
other_port_connection = double("other_port_connection", :closed? => false)
|
125
|
+
other_port_server = Paperclip::Storage::Ftp::Server.new(
|
126
|
+
:host => server.host,
|
127
|
+
:port => server.port + 1
|
128
|
+
)
|
129
|
+
other_port_server.should_receive(:build_connection).once.and_return(other_port_connection)
|
130
|
+
other_port_server.connection.should == other_port_connection
|
131
|
+
end
|
132
|
+
|
133
|
+
it "reconnects if the connection is closed" do
|
134
|
+
connection = double("connection", :closed? => true)
|
135
|
+
server.stub(:build_connection) { connection }
|
136
|
+
connection.should_receive(:connect).with(server.host, server.port)
|
137
|
+
connection.should_receive(:login).with(server.user, server.password)
|
138
|
+
server.connection.should == connection
|
84
139
|
end
|
85
140
|
end
|
86
141
|
|
87
142
|
context "mkdir_p" do
|
143
|
+
before do
|
144
|
+
server.stub(:connection).and_return(double("connection"))
|
145
|
+
end
|
146
|
+
|
88
147
|
it "creates the directory and all its parent directories" do
|
89
|
-
server.connection = double("connection")
|
90
148
|
server.connection.should_receive(:mkdir).with("/").ordered
|
91
149
|
server.connection.should_receive(:mkdir).with("/files").ordered
|
92
150
|
server.connection.should_receive(:mkdir).with("/files/foo").ordered
|
@@ -95,7 +153,6 @@ describe Paperclip::Storage::Ftp::Server do
|
|
95
153
|
end
|
96
154
|
|
97
155
|
it "does not stop on Net::FTPPermError" do
|
98
|
-
server.connection = double("connection")
|
99
156
|
server.connection.should_receive(:mkdir).with("/").and_raise(Net::FTPPermError)
|
100
157
|
server.connection.should_receive(:mkdir).with("/files")
|
101
158
|
server.mkdir_p("/files")
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paperclip-storage-ftp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Sebastian Röbke
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: paperclip
|
@@ -126,15 +126,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
126
126
|
- - ! '>='
|
127
127
|
- !ruby/object:Gem::Version
|
128
128
|
version: '0'
|
129
|
-
segments:
|
130
|
-
- 0
|
131
|
-
hash: -504637831743076511
|
132
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
130
|
none: false
|
134
131
|
requirements:
|
135
|
-
- - ! '
|
132
|
+
- - ! '>='
|
136
133
|
- !ruby/object:Gem::Version
|
137
|
-
version:
|
134
|
+
version: '0'
|
138
135
|
requirements: []
|
139
136
|
rubyforge_project:
|
140
137
|
rubygems_version: 1.8.24
|