carrierwave-neo4j 2.0.4 → 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 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