carrierwave-neo4j 2.0.4 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 91d3e9f15343156db10c1a79b7e94d5767a3c4b4
4
- data.tar.gz: 2092abf2bd8f474e25bdd6d6ff9acb2959353eb7
2
+ SHA256:
3
+ metadata.gz: ee1ece089b8cbd55532f4c0cba7a7a19054b24edc86f81a077c5497c49f4c801
4
+ data.tar.gz: a8a1b8fb5355129bfb9fd41839b59bbeee38e5808d59cac0a21fcc7ee6291a55
5
5
  SHA512:
6
- metadata.gz: f2a94567dbb5049112b24f41b4f728d56cd55722ae43f011bb877cdc729a739888460d5171eac7550c8d89e31a7e457c348a0ff074d0878236ada9a38b01a1d6
7
- data.tar.gz: 3932cac7fea54e9076f23b60f4bd489ba5e1e92f9eceac46198a87c396219832587e484a91bbebeddcc18e27ed1349392f75f335f118cfff4237bf99f2beeb5e
6
+ metadata.gz: f2adb7d1d88b7f225d2d89c4bdcae75ada1f4fa3edfc5679cbd0aa034c80d6738bc2990dc9a2527555ae92837edbf9f447fb0ed811c9da133d2613c88019dd45
7
+ data.tar.gz: e9168769c2f8e656c3e8e1046e5c7d5fbaaec1d53269525557fe50b3f4a77ba08aa0966529cd5835750b4fe57b7b7a85b5e58aea3ac145b151f93e6c451b9a97
data/.gitignore CHANGED
@@ -6,3 +6,6 @@ db/*
6
6
  .idea
7
7
 
8
8
  .ruby-version
9
+ spec/public/uploads/*
10
+ bin/
11
+
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
+ ## [3.0.0] - 2020-07-15
8
+
9
+ ### Fixed
10
+
11
+ - Updated and fixed all tests to work with neo4j.rb 9.x and CarrierWave 2.x
12
+ - Updated the overall format of the plugin to mirror CarrierWave::Orm::ActiveRecord as much as possible
13
+ - Files are now deleted correctly on `#destroy`
14
+ - File information is now correctly reloaded on `#find`
15
+ - Thanks @deobald for all the fixes.
16
+
7
17
  ## [2.0.4] - 2018-04-03
8
18
 
9
19
  ### Fixed
data/Gemfile CHANGED
@@ -2,10 +2,3 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in carrierwave_neo4j.gemspec
4
4
  gemspec
5
-
6
- gem 'neo4j', github: 'neo4jrb/neo4j'
7
- gem 'neo4j-core', github: 'neo4jrb/neo4j-core'
8
- #gem 'carrierwave', '0.10.0'
9
- gem 'pry'
10
- gem 'rspec-its'
11
- gem 'database_cleaner', github: 'dpisarewski/database_cleaner', branch: 'neo4j'
data/README.md CHANGED
@@ -1,21 +1,81 @@
1
1
  ## CarrierWave for Neo4j
2
2
 
3
- This gem adds support for Neo4j 3.0+ to CarrierWave, see the CarrierWave documentation for more detailed usage instructions.
3
+ This gem adds support for Neo4j 3.0+ (neo4j.rb 9.6.0+) to CarrierWave 2.1.0+, see the CarrierWave documentation for more detailed usage instructions.
4
4
 
5
5
  ### Installation Instructions
6
6
 
7
7
  Add to your Gemfile:
8
8
 
9
9
  ```ruby
10
- gem 'carrierwave-neo4j', require: 'carrierwave/neo4j'
10
+ gem 'carrierwave-neo4j', '~> 3.0', require: 'carrierwave/neo4j'
11
11
  ```
12
- Use it like this:
12
+
13
+ You can see example usage in `spec/neo4j_realistic_spec.rb` but in brief, you can use it like this:
13
14
 
14
15
  ```ruby
16
+ class AttachmentUploader < CarrierWave::Uploader::Base
17
+ storage :file
18
+
19
+ def store_dir
20
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
21
+ end
22
+ end
23
+
15
24
  class Asset
16
25
  include Neo4j::ActiveNode
17
26
 
18
27
  property :attachment, type: String
19
28
  mount_uploader :attachment, AttachmentUploader
20
29
  end
21
- ```
30
+ ```
31
+
32
+ If you want image manipulation, you will need to install ImageMagick
33
+
34
+ On Ubuntu:
35
+
36
+ ```sh
37
+ sudo apt-get install imagemagick --fix-missing
38
+ ```
39
+
40
+ On macOS:
41
+
42
+ ```sh
43
+ brew install imagemagick
44
+ ```
45
+
46
+ ### Development
47
+
48
+ ```sh
49
+ bundle install
50
+ rake neo4j:install[community-latest,test]
51
+ rake neo4j:start[test]
52
+ rake spec
53
+ ```
54
+
55
+ ### Troubleshooting
56
+
57
+ #### Files are nil
58
+
59
+ If you aren't getting your files back after querying a record from Neo4j, be aware that this will only happen automatically for the `Model#find` method. For all other finders (`#all`, `#first`, `#find_by`, `#find_by_*`, `#find_by_*!`, `#last`) you will need to force a reload so the model sees the file. For example:
60
+
61
+ ```ruby
62
+ users = User.all
63
+ users.each(&:reload_from_database!)
64
+ ```
65
+
66
+ Sorry, this sucks. But this is a limitation of Neo4j.rb as these other finders don't fire any callbacks.
67
+
68
+ #### binstubs (particularly `bin/rspec`) seem broken
69
+
70
+ If you're getting some infinite recursion when you run the specs that ultimately results in an error like:
71
+
72
+ ```
73
+ `ensure in require': CRITICAL: RUBYGEMS_ACTIVATION_MONITOR.owned?: before false -> after true (RuntimeError)
74
+ ```
75
+
76
+ You may want to try:
77
+
78
+ ```sh
79
+ rm .bundle/config
80
+ bundle install
81
+ ```
data/Rakefile CHANGED
@@ -1 +1,12 @@
1
1
  require 'bundler/gem_tasks'
2
+ require 'neo4j/rake_tasks'
3
+
4
+ begin
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ task :default => :spec
10
+ rescue LoadError
11
+ puts "RSpec not installed...?"
12
+ end
@@ -7,19 +7,21 @@ Gem::Specification.new do |s|
7
7
  s.version = CarrierWave::Neo4j::VERSION
8
8
  s.authors = ["Rodrigo Navarro"]
9
9
  s.email = ["navarro@manapot.com.br"]
10
- s.homepage = "https://github.com/reu/carrierwave-neo4j"
10
+ s.homepage = "https://github.com/neo4jrb/carrierwave-neo4j"
11
11
  s.summary = %q{Neo4j support for Carrierwave}
12
12
  s.description = %q{Neo4j support for Carrierwave}
13
13
 
14
- s.rubyforge_project = "carrierwave_neo4j"
15
-
16
14
  s.files = `git ls-files`.split("\n")
17
15
  s.test_files = `git ls-files -- {spec}/*`.split("\n")
18
16
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
17
  s.require_paths = ["lib"]
20
18
 
21
- s.add_dependency("activesupport", ">= 3.0" )
22
- s.add_dependency("neo4j", ">= 3.0.0")
23
- s.add_dependency("carrierwave", ">= 0.5")
24
- s.add_development_dependency("rspec", "~> 2.0")
19
+ s.add_dependency("activesupport", ">= 6.0" )
20
+ s.add_dependency("neo4j", "~> 9.6.0")
21
+ s.add_dependency("carrierwave", ">= 2.1")
22
+ s.add_development_dependency("rspec", "~> 3.0")
23
+ s.add_development_dependency("rspec-its")
24
+ s.add_development_dependency("webmock")
25
+ s.add_development_dependency("neo4j-rake_tasks")
26
+ s.add_development_dependency("rake")
25
27
  end
@@ -5,69 +5,143 @@ require "carrierwave/validations/active_model"
5
5
  require "carrierwave/neo4j/uploader_converter"
6
6
  require "active_support/concern"
7
7
 
8
+ ######
9
+ # This file attempts to maintain symmetry with:
10
+ # https://github.com/carrierwaveuploader/carrierwave/blob/master/lib/carrierwave/orm/activerecord.rb
11
+ #
12
+ # Behaviours linked to callbacks (ex. `after_save :"store_#{column}!"`) belong to:
13
+ # https://github.com/carrierwaveuploader/carrierwave/blob/master/lib/carrierwave/mount.rb
14
+ # ...which is mixed into Model classes.
15
+ ######
8
16
  module CarrierWave
9
17
  module Neo4j
10
- extend ActiveSupport::Concern
11
18
 
19
+ # this class methods junk is necessary because ActiveNode is implemented as
20
+ # a model instead of a class for god-knows-what-reason.
21
+ extend ActiveSupport::Concern
12
22
  module ClassMethods
23
+
13
24
  include CarrierWave::Mount
25
+
14
26
  ##
15
27
  # See +CarrierWave::Mount#mount_uploader+ for documentation
16
28
  #
17
- def mount_uploader(column, uploader = nil, options = {}, &block)
29
+ def mount_uploader(column, uploader=nil, options={}, &block)
18
30
  super
19
31
 
32
+ mod = Module.new
33
+ prepend mod
34
+ mod.class_eval <<-RUBY, __FILE__, __LINE__+1
35
+ def remote_#{column}_url=(url)
36
+ column = _mounter(:#{column}).serialization_column
37
+ __send__(:"\#{column}_will_change!")
38
+ super
39
+ end
40
+ RUBY
41
+ end
42
+
43
+ ##
44
+ # See +CarrierWave::Mount#mount_uploaders+ for documentation
45
+ #
46
+ def mount_uploaders(column, uploader=nil, options={}, &block)
47
+ super
48
+
49
+ mod = Module.new
50
+ prepend mod
51
+ mod.class_eval <<-RUBY, __FILE__, __LINE__+1
52
+ def remote_#{column}_urls=(url)
53
+ column = _mounter(:#{column}).serialization_column
54
+ __send__(:"\#{column}_will_change!")
55
+ super
56
+ end
57
+ RUBY
58
+ end
59
+
60
+ def add_reload_callback(method)
61
+ @_reload_callbacks = [] unless @_reload_callbacks
62
+ @_reload_callbacks << method unless @_reload_callbacks.include?(method)
63
+ end
64
+
65
+ def reload_callbacks
66
+ @_reload_callbacks
67
+ end
68
+
69
+ private
70
+
71
+ def mount_base(column, uploader=nil, options={}, &block)
72
+ super
73
+
74
+ # this seems necessary to prevent the _identifier from including
75
+ # the entire path ('img.jpg' vs. '/uploads/user/image/img.jpg')
20
76
  serialize column, ::CarrierWave::Uploader::Base
21
77
 
22
78
  include CarrierWave::Validations::ActiveModel
23
79
 
24
- validates_integrity_of column if uploader_option(column.to_sym, :validate_integrity)
80
+ validates_integrity_of column if uploader_option(column.to_sym, :validate_integrity)
25
81
  validates_processing_of column if uploader_option(column.to_sym, :validate_processing)
82
+ validates_download_of column if uploader_option(column.to_sym, :validate_download)
83
+
84
+ # carrierwave keeps a instance variable of @uploaders, cached at init time
85
+ # but at init time, the value of the column is not yet available
86
+ # so after init, the empty @uploaders cache must be invalidated
87
+ # it will reinitialized with the processed column value on first access
88
+ after_initialize :_set_uploaders_nil
26
89
 
27
- after_save :"store_#{column}!"
28
90
  before_save :"write_#{column}_identifier"
29
- before_destroy :"clear_#{column}"
91
+ after_save :"store_#{column}!"
92
+ # this 'after_update' hook doesn't seem necessary, but please
93
+ # don't remove it just in case it ever becomes necessary:
94
+ after_update :"mark_remove_#{column}_false"
30
95
  after_destroy :"remove_#{column}!"
96
+ after_find :"force_retrieve_#{column}"
97
+
98
+ add_reload_callback :"force_retrieve_#{column}"
99
+
100
+ # TRYING THIS OUT FROM MONGOID:
101
+ # TODO: copy the other mongoid adapter code over
102
+ # https://github.com/carrierwaveuploader/carrierwave-mongoid/blob/master/lib/carrierwave/mongoid.rb
103
+ before_update :"store_previous_changes_for_#{column}"
104
+ after_save :"remove_previously_stored_#{column}"
31
105
 
32
106
  class_eval <<-RUBY, __FILE__, __LINE__+1
33
- def #{column}=(new_file)
34
- column = _mounter(:#{column}).serialization_column
35
- send(:attribute_will_change!, :#{column})
36
- super
37
- end
38
-
39
- def remote_#{column}_url=(url)
40
- column = _mounter(:#{column}).serialization_column
41
- send(:attribute_will_change!, :#{column})
42
- super
43
- end
44
-
45
- def clear_#{column}
46
- write_uploader(_mounter(:#{column}).serialization_column, nil)
47
- end
48
-
49
- def read_uploader(name)
50
- send(:attribute, name.to_s)
51
- end
52
-
53
- def write_uploader(name, value)
54
- send(:attribute=, name.to_s, value)
55
- end
56
-
57
- def reload_from_database
58
- if reloaded = self.class.load_entity(neo_id)
59
- send(:attributes=, reloaded.attributes.reject{ |k,v| v.is_a?(::CarrierWave::Uploader::Base) })
107
+
108
+ # def remote_#{column}_url=(url) is defined in 'mount_uploader'
109
+
110
+ def #{column}=(new_file)
111
+ column = _mounter(:#{column}).serialization_column
112
+ if !(new_file.blank? && __send__(:#{column}).blank?)
113
+ __send__(:"\#{column}_will_change!")
114
+ end
115
+ super
60
116
  end
61
- reloaded
62
- end
63
117
 
64
- # carrierwave keeps a instance variable of @uploaders, cached at init time
65
- # but at init time, the value of the column is not yet available
66
- # so after init, the empty @uploaders cache must be invalidated
67
- # it will reinitialized with the processed column value on first access
68
- unless method_defined?(:_set_uploaders_nil)
118
+ def remove_#{column}=(value)
119
+ column = _mounter(:#{column}).serialization_column
120
+ result = super
121
+ __send__(:"\#{column}_will_change!") if _mounter(:#{column}).remove?
122
+ result
123
+ end
69
124
 
70
- after_initialize :_set_uploaders_nil
125
+ def remove_#{column}!
126
+ self.remove_#{column} = true
127
+ write_#{column}_identifier
128
+ self.remove_#{column} = false
129
+ super
130
+ end
131
+
132
+ # Reset cached mounter on record reload
133
+ def reload(*)
134
+ _set_uploaders_nil
135
+ @_mounters = nil
136
+ super
137
+ end
138
+
139
+ # Reset cached mounter on record dup
140
+ def initialize_dup(other)
141
+ _set_uploaders_nil
142
+ @_mounters = nil
143
+ super
144
+ end
71
145
 
72
146
  def _set_uploaders_nil
73
147
  if @_mounters
@@ -76,12 +150,62 @@ module CarrierWave
76
150
  end
77
151
  end
78
152
  end
79
- end
153
+
154
+ def _force_uploaders_reload
155
+ @_mounters.each do |_, mounter|
156
+ mounter.send(:uploaders)
157
+ end
158
+ end
159
+
160
+ # okay, this actually works:
161
+ def force_retrieve_#{column}
162
+ send(:#{column}).send(:retrieve_from_store!, #{column}_identifier)
163
+ end
164
+
165
+ # these produce an infinite loop, so... don't reintroduce them:
166
+ # alias_method :read_uploader, :read_attribute
167
+ # alias_method :write_uploader, :write_attribute
168
+ # public :read_uploader
169
+ # public :write_uploader
170
+
171
+ def read_uploader(name)
172
+ send(:attribute, name.to_s)
173
+ end
174
+
175
+ def write_uploader(name, value)
176
+ send(:attribute=, name.to_s, value)
177
+ end
178
+
179
+ def reload_from_database
180
+ if reloaded = self.class.load_entity(neo_id)
181
+ self.class.reload_callbacks.each { |m| reloaded.send(m) }
182
+ end
183
+ reloaded
184
+ end
185
+
186
+ def reload_from_database!
187
+ if reloaded = self.class.load_entity(neo_id)
188
+ send(:attributes=, reloaded.attributes)
189
+ self.class.reload_callbacks.each { |m| send(m) }
190
+ end
191
+ self
192
+ end
193
+
194
+ # MONGOID:
195
+ # CarrierWave 1.1 references ::ActiveRecord constant directly which
196
+ # will fail in projects without ActiveRecord. We need to overwrite this
197
+ # method to avoid it.
198
+ # See https://github.com/carrierwaveuploader/carrierwave/blob/07dc4d7bd7806ab4b963cf8acbad73d97cdfe74e/lib/carrierwave/mount.rb#L189
199
+ def store_previous_changes_for_#{column}
200
+ @_previous_changes_for_#{column} = changes[_mounter(:#{column}).serialization_column]
201
+ end
202
+
80
203
  RUBY
81
204
  end
82
- end
83
205
 
206
+
207
+ end
84
208
  end
85
209
  end
86
210
 
87
- Neo4j::ActiveNode.send :include, CarrierWave::Neo4j
211
+ Neo4j::ActiveNode.include CarrierWave::Neo4j
@@ -7,7 +7,11 @@ module CarrierWave::Neo4j
7
7
  end
8
8
 
9
9
  def to_db(value)
10
- value.identifier
10
+ if value.is_a?(Array)
11
+ value.map(&:identifier)
12
+ else
13
+ value.identifier
14
+ end
11
15
  end
12
16
 
13
17
  def to_ruby(value)
@@ -1,5 +1,5 @@
1
1
  module CarrierWave
2
2
  module Neo4j
3
- VERSION = '2.0.4'
3
+ VERSION = '3.0.0'
4
4
  end
5
5
  end
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,13 @@
1
+
2
+ require "neo4j"
3
+
4
+ class FakeBookMigration < Neo4j::Migrations::Base
5
+
6
+ def self.create
7
+ FakeBookMigration.new(:fake_book_migration)
8
+ end
9
+
10
+ def up
11
+ add_constraint :Book, :uuid, force: true
12
+ end
13
+ 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,13 @@
1
+
2
+ require "neo4j"
3
+
4
+ class FakeUserMigration < Neo4j::Migrations::Base
5
+
6
+ def self.create
7
+ FakeUserMigration.new(:fake_user_migration)
8
+ end
9
+
10
+ def up
11
+ add_constraint :User, :uuid, force: true
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+
2
+ require "neo4j"
3
+
4
+ class FilesystemCleaner
5
+ def self.clean
6
+ FilesystemCleaner.new.clean_fs
7
+ end
8
+
9
+ def clean_fs
10
+ FileUtils.rm_rf("spec/public/uploads")
11
+ end
12
+ 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
@@ -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 extension_white_list
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 Tarja"
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) { reset_class }
33
- let(:user_class_png) { reset_class(PngUploader) }
34
- let(:user_class_error) { reset_class(ProcessingErrorUploader) }
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(:record) { user_class.new }
43
- subject { record.image }
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
- record.image = ""
52
- record.save
53
- record.reload
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
- record.image = File.open(file_path("tarja.jpg"))
62
- record.save
63
- record.reload
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/tarja.jpg") }
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(:record) { user_class.new }
111
+ let(:user) { user_class.new }
74
112
 
75
113
  before do
76
- record.image = File.open(file_path("tarja.jpg"))
77
- record.save
114
+ user.image = File.open(file_path("ong.jpg"))
115
+ user.save
78
116
 
79
- record.remove_image = true
80
- record.save
81
- record.reload
117
+ user.remove_image = true
118
+ user.save
119
+ user.reload
82
120
  end
83
121
 
84
- subject { record }
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("tarja.jpg"))
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("tarja.jpg"))
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,19 +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(:record) { user_class.new }
187
+ let(:user) { user_class.new }
112
188
 
113
189
  before do
114
- record.image = File.open(file_path("tarja.jpg"))
115
- record.save
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
- file_path = record.image.path
120
- expect { record.destroy }.to change {
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 {
121
198
  File.exist? file_path
122
199
  }.from(true).to(false)
123
200
  end
124
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
125
243
  end
@@ -1,11 +1,18 @@
1
1
  require "rubygems"
2
2
  require "bundler/setup"
3
+ require "rake"
3
4
  require "rspec"
4
5
  require "rspec/its"
6
+ require "webmock/rspec"
7
+
8
+ require "neo4j"
9
+ require "neo4j/core/cypher_session/adaptors/bolt"
10
+ require "helpers/database_cleaner"
11
+ require "helpers/filesystem_cleaner"
12
+ require "helpers/fake_migrations"
5
13
 
6
14
  require "carrierwave"
7
15
  require "carrierwave/neo4j"
8
- require "database_cleaner"
9
16
 
10
17
  def file_path(*paths)
11
18
  File.expand_path(File.join(File.dirname(__FILE__), "fixtures", *paths))
@@ -15,16 +22,26 @@ def public_path(*paths)
15
22
  File.expand_path(File.join(File.dirname(__FILE__), "public", *paths))
16
23
  end
17
24
 
25
+ def tmp_path( *paths )
26
+ File.expand_path(File.join(File.dirname(__FILE__), 'public/uploads/tmp', *paths))
27
+ end
28
+
18
29
  CarrierWave.root = public_path
19
- DatabaseCleaner[:neo4j, connection: {type: :server_db, path: 'http://localhost:7475'}].strategy = :transaction
30
+ # DatabaseCleaner[:neo4j, connection: {type: :bolt, path: 'bolt://localhost:7006'}].strategy = :transaction
31
+
32
+ neo4j_adaptor = Neo4j::Core::CypherSession::Adaptors::Bolt.new('bolt://localhost:7472', {ssl: false})
33
+ Neo4j::ActiveBase.on_establish_session { Neo4j::Core::CypherSession.new(neo4j_adaptor) }
20
34
 
21
35
  RSpec.configure do |config|
22
36
  config.before(:each) do
23
- DatabaseCleaner.start
37
+ DatabaseCleaner.avoid_validation do
38
+ DatabaseCleaner.clean
39
+ FilesystemCleaner.clean
40
+ FakeMigrations.migrate(:up)
41
+ end
24
42
  end
25
43
 
26
44
  config.after(:each) do
27
- DatabaseCleaner.clean
45
+ DatabaseCleaner.avoid_validation { DatabaseCleaner.clean }
28
46
  end
29
47
  end
30
-
metadata CHANGED
@@ -1,71 +1,127 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carrierwave-neo4j
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.4
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Navarro
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-04 00:00:00.000000000 Z
11
+ date: 2020-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activesupport
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: '3.0'
20
- type: :runtime
18
+ version: '6.0'
19
+ name: activesupport
21
20
  prerelease: false
21
+ type: :runtime
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '3.0'
26
+ version: '6.0'
27
27
  - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 9.6.0
28
33
  name: neo4j
34
+ prerelease: false
35
+ type: :runtime
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 9.6.0
41
+ - !ruby/object:Gem::Dependency
29
42
  requirement: !ruby/object:Gem::Requirement
30
43
  requirements:
31
44
  - - ">="
32
45
  - !ruby/object:Gem::Version
33
- version: 3.0.0
46
+ version: '2.1'
47
+ name: carrierwave
48
+ prerelease: false
34
49
  type: :runtime
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '2.1'
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
+ name: rspec
62
+ prerelease: false
63
+ type: :development
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ name: rspec-its
35
76
  prerelease: false
77
+ type: :development
36
78
  version_requirements: !ruby/object:Gem::Requirement
37
79
  requirements:
38
80
  - - ">="
39
81
  - !ruby/object:Gem::Version
40
- version: 3.0.0
82
+ version: '0'
41
83
  - !ruby/object:Gem::Dependency
42
- name: carrierwave
43
84
  requirement: !ruby/object:Gem::Requirement
44
85
  requirements:
45
86
  - - ">="
46
87
  - !ruby/object:Gem::Version
47
- version: '0.5'
48
- type: :runtime
88
+ version: '0'
89
+ name: webmock
49
90
  prerelease: false
91
+ type: :development
50
92
  version_requirements: !ruby/object:Gem::Requirement
51
93
  requirements:
52
94
  - - ">="
53
95
  - !ruby/object:Gem::Version
54
- version: '0.5'
96
+ version: '0'
55
97
  - !ruby/object:Gem::Dependency
56
- name: rspec
57
98
  requirement: !ruby/object:Gem::Requirement
58
99
  requirements:
59
- - - "~>"
100
+ - - ">="
60
101
  - !ruby/object:Gem::Version
61
- version: '2.0'
102
+ version: '0'
103
+ name: neo4j-rake_tasks
104
+ prerelease: false
62
105
  type: :development
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ name: rake
63
118
  prerelease: false
119
+ type: :development
64
120
  version_requirements: !ruby/object:Gem::Requirement
65
121
  requirements:
66
- - - "~>"
122
+ - - ">="
67
123
  - !ruby/object:Gem::Version
68
- version: '2.0'
124
+ version: '0'
69
125
  description: Neo4j support for Carrierwave
70
126
  email:
71
127
  - navarro@manapot.com.br
@@ -85,13 +141,22 @@ files:
85
141
  - lib/carrierwave/neo4j.rb
86
142
  - lib/carrierwave/neo4j/uploader_converter.rb
87
143
  - lib/carrierwave/neo4j/version.rb
88
- - spec/fixtures/tarja.jpg
144
+ - spec/fixtures/neo4j.png
145
+ - spec/fixtures/ong.jpg
146
+ - spec/helpers/database_cleaner.rb
147
+ - spec/helpers/fake_book_migration.rb
148
+ - spec/helpers/fake_migrations.rb
149
+ - spec/helpers/fake_schema_migration.rb
150
+ - spec/helpers/fake_user_migration.rb
151
+ - spec/helpers/filesystem_cleaner.rb
152
+ - spec/neo4j_realistic_spec.rb
153
+ - spec/neo4j_sanity_spec.rb
89
154
  - spec/neo4j_spec.rb
90
155
  - spec/spec_helper.rb
91
- homepage: https://github.com/reu/carrierwave-neo4j
156
+ homepage: https://github.com/neo4jrb/carrierwave-neo4j
92
157
  licenses: []
93
158
  metadata: {}
94
- post_install_message:
159
+ post_install_message:
95
160
  rdoc_options: []
96
161
  require_paths:
97
162
  - lib
@@ -106,9 +171,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
171
  - !ruby/object:Gem::Version
107
172
  version: '0'
108
173
  requirements: []
109
- rubyforge_project: carrierwave_neo4j
110
- rubygems_version: 2.6.13
111
- signing_key:
174
+ rubyforge_project:
175
+ rubygems_version: 2.7.10
176
+ signing_key:
112
177
  specification_version: 4
113
178
  summary: Neo4j support for Carrierwave
114
179
  test_files: []
Binary file