carrierwave-neo4j 2.0.0 → 3.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.
- checksums.yaml +5 -5
- data/.gitignore +3 -0
- data/CHANGELOG.md +35 -0
- data/Gemfile +0 -2
- data/README.md +64 -4
- data/Rakefile +11 -0
- data/carrierwave-neo4j.gemspec +9 -7
- data/lib/carrierwave/neo4j.rb +177 -41
- data/lib/carrierwave/neo4j/uploader_converter.rb +16 -6
- data/lib/carrierwave/neo4j/version.rb +1 -1
- data/spec/fixtures/neo4j.png +0 -0
- data/spec/fixtures/ong.jpg +0 -0
- data/spec/helpers/database_cleaner.rb +29 -0
- data/spec/helpers/fake_book_migration.rb +13 -0
- data/spec/helpers/fake_migrations.rb +12 -0
- data/spec/helpers/fake_schema_migration.rb +13 -0
- data/spec/helpers/fake_user_migration.rb +13 -0
- data/spec/helpers/filesystem_cleaner.rb +12 -0
- data/spec/neo4j_realistic_spec.rb +104 -0
- data/spec/neo4j_sanity_spec.rb +137 -0
- data/spec/neo4j_spec.rb +148 -29
- data/spec/spec_helper.rb +23 -5
- metadata +91 -26
- data/spec/fixtures/tarja.jpg +0 -0
Binary file
|
Binary file
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
require "neo4j"
|
3
|
+
|
4
|
+
class DatabaseCleaner
|
5
|
+
include Neo4j::Migrations::Helpers
|
6
|
+
|
7
|
+
def self.clean
|
8
|
+
DatabaseCleaner.new.clean_db
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.avoid_validation
|
12
|
+
# migrations and db cleanup have to happen outside of validations
|
13
|
+
# or they never succeed
|
14
|
+
Neo4j::Migrations.currently_running_migrations = true
|
15
|
+
yield
|
16
|
+
Neo4j::Migrations.currently_running_migrations = false
|
17
|
+
end
|
18
|
+
|
19
|
+
def clean_db
|
20
|
+
execute("match (n) detach delete n;")
|
21
|
+
execute("call db.constraints").each do |constraint|
|
22
|
+
execute "drop #{constraint[:description]}"
|
23
|
+
end
|
24
|
+
execute("call db.indexes").each do |index|
|
25
|
+
execute "drop #{index[:description]}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
require 'helpers/fake_schema_migration'
|
3
|
+
require 'helpers/fake_user_migration'
|
4
|
+
require 'helpers/fake_book_migration'
|
5
|
+
|
6
|
+
class FakeMigrations
|
7
|
+
def self.migrate(direction)
|
8
|
+
FakeSchemaMigration.create.migrate(direction)
|
9
|
+
FakeUserMigration.create.migrate(direction)
|
10
|
+
FakeBookMigration.create.migrate(direction)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
require "neo4j"
|
3
|
+
|
4
|
+
class FakeSchemaMigration < Neo4j::Migrations::Base
|
5
|
+
|
6
|
+
def self.create
|
7
|
+
FakeSchemaMigration.new(:fake_schema_migration)
|
8
|
+
end
|
9
|
+
|
10
|
+
def up
|
11
|
+
add_constraint :"Neo4j::Migrations::SchemaMigration", :migration_id, force: true
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
# RealisticUploader and Book exist to provide a basic test harness with
|
4
|
+
# standard Ruby code and no metaprogramming of any sort. Because that
|
5
|
+
# stuff is really hard to trust, even when you're sure you got it right.
|
6
|
+
|
7
|
+
class RealisticUploader < CarrierWave::Uploader::Base
|
8
|
+
include CarrierWave::MiniMagick
|
9
|
+
|
10
|
+
storage :file
|
11
|
+
|
12
|
+
def store_dir
|
13
|
+
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def extension_whitelist
|
17
|
+
%w(jpg jpeg gif png)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Book
|
22
|
+
include Neo4j::ActiveNode
|
23
|
+
property :cover, type: String
|
24
|
+
mount_uploader :cover, RealisticUploader
|
25
|
+
end
|
26
|
+
|
27
|
+
describe CarrierWave::Neo4j do
|
28
|
+
after do
|
29
|
+
Book.destroy_all
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#uploader" do
|
33
|
+
let(:book) { Book.new }
|
34
|
+
subject { book.cover }
|
35
|
+
|
36
|
+
context "when nothing is assigned" do
|
37
|
+
it { should be_blank }
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when a file is stored to a store_dir" do
|
41
|
+
before do
|
42
|
+
book.cover = File.open(file_path("ong.jpg"))
|
43
|
+
book.save
|
44
|
+
book.reload
|
45
|
+
end
|
46
|
+
|
47
|
+
it { should be_an_instance_of RealisticUploader }
|
48
|
+
its(:current_path) { should == public_path("uploads/book/cover/#{book.id}/ong.jpg") }
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when a db lookup uses `#find`" do
|
52
|
+
before do
|
53
|
+
book.cover = File.open(file_path("ong.jpg"))
|
54
|
+
book.save
|
55
|
+
@found = Book.find(book.id)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "has a basic identifier" do
|
59
|
+
expect(@found.cover_identifier).to eq "ong.jpg"
|
60
|
+
end
|
61
|
+
|
62
|
+
subject { @found.cover }
|
63
|
+
|
64
|
+
it { should be_an_instance_of RealisticUploader }
|
65
|
+
its(:url) { should == "/uploads/book/cover/#{book.id}/ong.jpg"}
|
66
|
+
its(:current_path) { should == public_path("uploads/book/cover/#{book.id}/ong.jpg") }
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when a db look up does not use `#find`" do
|
70
|
+
before do
|
71
|
+
book.cover = File.open(file_path("ong.jpg"))
|
72
|
+
book.save
|
73
|
+
@found = Book.find_by_id(book.id)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "has a basic identifier" do
|
77
|
+
expect(@found.cover_identifier).to eq "ong.jpg"
|
78
|
+
end
|
79
|
+
|
80
|
+
subject { @found.cover }
|
81
|
+
|
82
|
+
# There is no way around this. `#url` and `#current_path` depend on the
|
83
|
+
# retrieval of the file from the store but there the only callback
|
84
|
+
# available is `:after_find` which does not fire on `#find_by` queries.
|
85
|
+
it { should be_an_instance_of RealisticUploader }
|
86
|
+
its(:url) { should be_nil }
|
87
|
+
its(:current_path) { should be_nil }
|
88
|
+
|
89
|
+
it "is retrieved with `#reload_from_database!`" do
|
90
|
+
@found.reload_from_database!
|
91
|
+
expect(@found.cover.url).to eq("/uploads/book/cover/#{@found.id}/ong.jpg")
|
92
|
+
expect(@found.cover.current_path).to eq(public_path("uploads/book/cover/#{@found.id}/ong.jpg"))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with CarrierWave::MiniMagick" do
|
97
|
+
it "has width and height" do
|
98
|
+
book.cover = File.open(file_path("ong.jpg"))
|
99
|
+
expect(book.cover.width).to eq 273
|
100
|
+
expect(book.cover.height).to eq 273
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
# This spec mirrors the specs found in the CarrierWave::Orm::ActiveRecord spec:
|
4
|
+
# https://github.com/carrierwaveuploader/carrierwave/blob/master/spec/orm/activerecord_spec.rb
|
5
|
+
#
|
6
|
+
# Use it to sanity-check behaviour since ActiveGraph and ActiveRecord are
|
7
|
+
# NOT symmetrical.
|
8
|
+
|
9
|
+
class DefaultUploader < CarrierWave::Uploader::Base ; end
|
10
|
+
|
11
|
+
def reset_class
|
12
|
+
Object.send(:remove_const, "User") rescue nil
|
13
|
+
Object.const_set("User", Class.new())
|
14
|
+
User.class_eval do
|
15
|
+
include Neo4j::ActiveNode
|
16
|
+
property :image, type: String
|
17
|
+
mount_uploader :image, DefaultUploader
|
18
|
+
end
|
19
|
+
User
|
20
|
+
end
|
21
|
+
|
22
|
+
describe CarrierWave::Neo4j do
|
23
|
+
before do
|
24
|
+
reset_class
|
25
|
+
@user = User.new
|
26
|
+
end
|
27
|
+
|
28
|
+
after do
|
29
|
+
User.destroy_all
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "sanity checks" do
|
33
|
+
|
34
|
+
describe "#mount_uploader" do
|
35
|
+
before do
|
36
|
+
User.mount_uploader(:image, DefaultUploader)
|
37
|
+
@user = User.new
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns valid JSON when to_json is called when image is nil" do
|
41
|
+
expect(@user[:image]).to be_blank
|
42
|
+
hash = JSON.parse(@user.to_json)
|
43
|
+
expect(hash.keys).to include("user")
|
44
|
+
# ActiveRecord returns the user hash directly but Neo4j's `.to_json`
|
45
|
+
# requires that we select the user hash explicitly
|
46
|
+
user_hash = hash["user"]
|
47
|
+
expect(user_hash.keys).to include("image")
|
48
|
+
expect(user_hash["image"].keys).to include("url")
|
49
|
+
expect(user_hash["image"]["url"]).to be_nil
|
50
|
+
end
|
51
|
+
|
52
|
+
it "returns valid JSON when to_json is called when image is present" do
|
53
|
+
@user.image = File.open(file_path("ong.jpg"))
|
54
|
+
@user.save!
|
55
|
+
@user.reload
|
56
|
+
# again, ActiveRecord does not require the sub-select with `["user"]`
|
57
|
+
expect(JSON.parse(@user.to_json)["user"]["image"]).to eq({"url" => "/uploads/ong.jpg"})
|
58
|
+
end
|
59
|
+
|
60
|
+
it "does not return anything when a stub image is assigned" do
|
61
|
+
# ActiveRecord does permit square bracket assignment to a column
|
62
|
+
# Neo4j does not
|
63
|
+
@user[:image] = 'ong.jpg'
|
64
|
+
@user.save!
|
65
|
+
@user.reload
|
66
|
+
expect(@user.image).to be_blank
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#image" do
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#save" do
|
74
|
+
it "should do nothing when no file has been assigned" do
|
75
|
+
expect(@user.save).to be_truthy
|
76
|
+
expect(@user.image).to be_blank
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should assign the filename to the database" do
|
80
|
+
@user.image = File.open(file_path("ong.jpg"))
|
81
|
+
expect(@user.save).to be_truthy
|
82
|
+
@user.reload
|
83
|
+
# under ActiveRecord these would be equal
|
84
|
+
expect(@user[:image]).not_to eq('ong.jpg')
|
85
|
+
expect(@user[:image].identifier).to eq('ong.jpg')
|
86
|
+
expect(@user.image_identifier).to eq('ong.jpg')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#update" do
|
91
|
+
it "resets cached value on record reload" do
|
92
|
+
@user.image = File.open(file_path("ong.jpg"))
|
93
|
+
@user.save!
|
94
|
+
|
95
|
+
expect(@user.reload.image).to be_present
|
96
|
+
|
97
|
+
other = User.find(@user.id)
|
98
|
+
other.image = nil
|
99
|
+
other.save!
|
100
|
+
|
101
|
+
expect(@user.reload.image).to be_blank
|
102
|
+
end
|
103
|
+
|
104
|
+
it "does not respect `update_column`" do
|
105
|
+
@user.image = File.open(file_path("ong.jpg"))
|
106
|
+
@user.save!
|
107
|
+
|
108
|
+
# ActiveRecord would respect `update_column`
|
109
|
+
User.find(@user.id).update_column(:image, nil)
|
110
|
+
|
111
|
+
expect(@user.reload.image).to be_present
|
112
|
+
other = User.find(@user.id)
|
113
|
+
expect(other.image).to be_present
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "#destroy" do
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "#remote_image_url=" do
|
121
|
+
before do
|
122
|
+
stub_request(:get, "www.example.com/test.jpg").to_return(body: File.read(file_path("ong.jpg")))
|
123
|
+
end
|
124
|
+
|
125
|
+
it "marks image as changed when setting remote_image_url" do
|
126
|
+
expect(@user.image_changed?).to be_falsey
|
127
|
+
@user.remote_image_url = 'http://www.example.com/test.jpg'
|
128
|
+
expect(@user.image_changed?).to be_truthy
|
129
|
+
expect(File.exist?(public_path('uploads/test.jpg'))).to be_falsey
|
130
|
+
@user.save!
|
131
|
+
@user.reload
|
132
|
+
expect(File.exist?(public_path('uploads/test.jpg'))).to be_truthy
|
133
|
+
expect(@user.image_changed?).to be_falsey
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/spec/neo4j_spec.rb
CHANGED
@@ -12,10 +12,10 @@ class User
|
|
12
12
|
property :image, type: String
|
13
13
|
end
|
14
14
|
|
15
|
-
class DefaultUploader < CarrierWave::Uploader::Base; end
|
15
|
+
class DefaultUploader < CarrierWave::Uploader::Base ; end
|
16
16
|
|
17
17
|
class PngUploader < CarrierWave::Uploader::Base
|
18
|
-
def
|
18
|
+
def extension_whitelist
|
19
19
|
%w(png)
|
20
20
|
end
|
21
21
|
end
|
@@ -24,14 +24,21 @@ class ProcessingErrorUploader < CarrierWave::Uploader::Base
|
|
24
24
|
process :end_on_an_era
|
25
25
|
|
26
26
|
def end_on_an_era
|
27
|
-
raise CarrierWave::ProcessingError, "Bye
|
27
|
+
raise CarrierWave::ProcessingError, "Bye OngDB"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class DownloadErrorUploader < CarrierWave::Uploader::Base
|
32
|
+
def download!(file, headers = {})
|
33
|
+
raise CarrierWave::DownloadError
|
28
34
|
end
|
29
35
|
end
|
30
36
|
|
31
37
|
describe CarrierWave::Neo4j do
|
32
|
-
let(:user_class)
|
33
|
-
let(:user_class_png)
|
34
|
-
let(:user_class_error)
|
38
|
+
let(:user_class) { reset_class }
|
39
|
+
let(:user_class_png) { reset_class(PngUploader) }
|
40
|
+
let(:user_class_error) { reset_class(ProcessingErrorUploader) }
|
41
|
+
let(:user_download_error) { reset_class(DownloadErrorUploader) }
|
35
42
|
let(:user) { user_class.new }
|
36
43
|
|
37
44
|
after do
|
@@ -39,8 +46,8 @@ describe CarrierWave::Neo4j do
|
|
39
46
|
end
|
40
47
|
|
41
48
|
describe "#image" do
|
42
|
-
let(:
|
43
|
-
subject {
|
49
|
+
let(:user) { user_class.new }
|
50
|
+
subject { user.image }
|
44
51
|
|
45
52
|
context "when nothing is assigned" do
|
46
53
|
it { should be_blank }
|
@@ -48,9 +55,9 @@ describe CarrierWave::Neo4j do
|
|
48
55
|
|
49
56
|
context "when an empty string is assigned" do
|
50
57
|
before do
|
51
|
-
|
52
|
-
|
53
|
-
|
58
|
+
user.image = ""
|
59
|
+
user.save
|
60
|
+
user.reload
|
54
61
|
end
|
55
62
|
|
56
63
|
it { should be_blank }
|
@@ -58,30 +65,61 @@ describe CarrierWave::Neo4j do
|
|
58
65
|
|
59
66
|
context "when a filename is stored" do
|
60
67
|
before do
|
61
|
-
|
62
|
-
|
63
|
-
|
68
|
+
user.image = File.open(file_path("ong.jpg"))
|
69
|
+
user.save
|
70
|
+
user.reload
|
64
71
|
end
|
65
72
|
|
66
73
|
it { should be_an_instance_of DefaultUploader }
|
67
|
-
its(:current_path) { should == public_path("uploads/
|
74
|
+
its(:current_path) { should == public_path("uploads/ong.jpg") }
|
75
|
+
end
|
76
|
+
|
77
|
+
context "when a model is retrieved from the db" do
|
78
|
+
before do
|
79
|
+
user.image = File.open(file_path("ong.jpg"))
|
80
|
+
user.save
|
81
|
+
@found = user_class.find(user.uuid)
|
82
|
+
end
|
83
|
+
|
84
|
+
subject { @found.image }
|
85
|
+
|
86
|
+
it "has a basic identifier" do
|
87
|
+
expect(@found.image_identifier).to eq "ong.jpg"
|
88
|
+
end
|
89
|
+
|
90
|
+
it { should be_an_instance_of DefaultUploader }
|
91
|
+
its(:url) { should == "/uploads/ong.jpg"}
|
92
|
+
its(:current_path) { should == public_path("uploads/ong.jpg") }
|
68
93
|
end
|
69
94
|
end
|
70
95
|
|
71
96
|
describe "#save" do
|
97
|
+
context "when image= is assigned and the user is saved" do
|
98
|
+
let(:user) { user_class.new }
|
99
|
+
|
100
|
+
before do
|
101
|
+
user.image = File.open(file_path("ong.jpg"))
|
102
|
+
user.save
|
103
|
+
end
|
104
|
+
|
105
|
+
it "writes the file to disk" do
|
106
|
+
expect(File.exist?(public_path('uploads/ong.jpg'))).to be_truthy
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
72
110
|
context "when remove_image? is true" do
|
73
|
-
let(:
|
111
|
+
let(:user) { user_class.new }
|
74
112
|
|
75
113
|
before do
|
76
|
-
|
77
|
-
|
114
|
+
user.image = File.open(file_path("ong.jpg"))
|
115
|
+
user.save
|
78
116
|
|
79
|
-
|
80
|
-
|
81
|
-
|
117
|
+
user.remove_image = true
|
118
|
+
user.save
|
119
|
+
user.reload
|
82
120
|
end
|
83
121
|
|
84
|
-
subject {
|
122
|
+
subject { user }
|
85
123
|
|
86
124
|
its(:image) { should be_blank }
|
87
125
|
end
|
@@ -89,7 +127,7 @@ describe CarrierWave::Neo4j do
|
|
89
127
|
context "when validating integrity" do
|
90
128
|
subject do
|
91
129
|
user = user_class_png.new
|
92
|
-
user.image = File.open(file_path("
|
130
|
+
user.image = File.open(file_path("ong.jpg"))
|
93
131
|
user
|
94
132
|
end
|
95
133
|
|
@@ -99,7 +137,17 @@ describe CarrierWave::Neo4j do
|
|
99
137
|
context "when validating processing" do
|
100
138
|
subject do
|
101
139
|
user = user_class_error.new
|
102
|
-
user.image = File.open(file_path("
|
140
|
+
user.image = File.open(file_path("ong.jpg"))
|
141
|
+
user
|
142
|
+
end
|
143
|
+
|
144
|
+
it { should_not be_valid }
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'when validating download' do
|
148
|
+
subject do
|
149
|
+
user = user_download_error.new
|
150
|
+
user.remote_image_url = 'http://www.example.com/missing.jpg'
|
103
151
|
user
|
104
152
|
end
|
105
153
|
|
@@ -107,18 +155,89 @@ describe CarrierWave::Neo4j do
|
|
107
155
|
end
|
108
156
|
end
|
109
157
|
|
158
|
+
describe "#update" do
|
159
|
+
let(:user) { user_class.new }
|
160
|
+
|
161
|
+
before do
|
162
|
+
user.image = File.open(file_path("ong.jpg"))
|
163
|
+
user.save
|
164
|
+
end
|
165
|
+
|
166
|
+
it "does not flag the uploader for removal" do
|
167
|
+
user.image = File.open(file_path("neo4j.png"))
|
168
|
+
user.save
|
169
|
+
expect(user.remove_image?).to be_falsey
|
170
|
+
end
|
171
|
+
|
172
|
+
it "stores the updated file" do
|
173
|
+
user.image = File.open(file_path("neo4j.png"))
|
174
|
+
user.save
|
175
|
+
expect(user.image.current_path).to eq public_path('uploads/neo4j.png')
|
176
|
+
expect(user.image.url).to eq '/uploads/neo4j.png'
|
177
|
+
end
|
178
|
+
|
179
|
+
it "writes the updated file to disk" do
|
180
|
+
user.image = File.open(file_path("neo4j.png"))
|
181
|
+
user.save
|
182
|
+
expect(File.exist?(public_path('uploads/neo4j.png'))).to be_truthy
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
110
186
|
describe "#destroy" do
|
111
|
-
let(:
|
187
|
+
let(:user) { user_class.new }
|
112
188
|
|
113
189
|
before do
|
114
|
-
|
115
|
-
|
190
|
+
user.image = File.open(file_path("ong.jpg"))
|
191
|
+
user.save
|
116
192
|
end
|
117
193
|
|
118
194
|
it "also destroys the image" do
|
119
|
-
|
120
|
-
|
195
|
+
file_path = user.image.path
|
196
|
+
expect(user.image.current_path).to eq public_path('uploads/ong.jpg')
|
197
|
+
expect { user.destroy }.to change {
|
198
|
+
File.exist? file_path
|
121
199
|
}.from(true).to(false)
|
122
200
|
end
|
123
201
|
end
|
202
|
+
|
203
|
+
describe "#reload_from_database" do
|
204
|
+
context "when used without mutation" do
|
205
|
+
before do
|
206
|
+
user.image = File.open(file_path("ong.jpg"))
|
207
|
+
user.save
|
208
|
+
@reloaded = user.reload_from_database
|
209
|
+
end
|
210
|
+
|
211
|
+
subject { @reloaded.image }
|
212
|
+
|
213
|
+
it "has an id and image identifier" do
|
214
|
+
expect(@reloaded.id).to eq user.id
|
215
|
+
expect(@reloaded.image_identifier).to eq "ong.jpg"
|
216
|
+
end
|
217
|
+
|
218
|
+
it { should be_an_instance_of DefaultUploader }
|
219
|
+
its(:url) { should == "/uploads/ong.jpg"}
|
220
|
+
its(:current_path) { should == public_path("uploads/ong.jpg") }
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe "#reload_from_database!" do
|
225
|
+
context "when used with mutation" do
|
226
|
+
before do
|
227
|
+
user.image = File.open(file_path("ong.jpg"))
|
228
|
+
user.save
|
229
|
+
user.reload_from_database!
|
230
|
+
end
|
231
|
+
|
232
|
+
subject { user.image }
|
233
|
+
|
234
|
+
it "has an image identifier" do
|
235
|
+
expect(user.image_identifier).to eq "ong.jpg"
|
236
|
+
end
|
237
|
+
|
238
|
+
it { should be_an_instance_of DefaultUploader }
|
239
|
+
its(:url) { should == "/uploads/ong.jpg"}
|
240
|
+
its(:current_path) { should == public_path("uploads/ong.jpg") }
|
241
|
+
end
|
242
|
+
end
|
124
243
|
end
|