dumped_railers 0.1.5 → 0.2.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
2
  SHA256:
3
- metadata.gz: 80d7da9c36ba41d750a56d9ee58ed12bfadb816f0f4dde5e915590811344541d
4
- data.tar.gz: 28376d6a5b35a1e63be22573bb0180dc0d4d765c6064204b6eca49c70bac5748
3
+ metadata.gz: 5faab9a280ca3d2e4e4379074ab56846ba2a1c1b65969a272efdf4fd344d8c20
4
+ data.tar.gz: fa3a52e63c010d51f023fc2815d058dfb8e4b05652f6e6d57893784faa679c53
5
5
  SHA512:
6
- metadata.gz: c26bb04f7cba72d1f397294133c4bd32ebad630fb62d37ee3649fee40341380040ba271ebdde8410ffd263175eed4e6432a623eb6840016fe7638c21825f1d58
7
- data.tar.gz: 933f85c32bd8390ff4d7f9827cc8d58742dc5c7ebf629b744fd35db010526ef2d389875c85170f8d939784a52a76d98579e8e8cd2721fa3b5a571c7910bbac8e
6
+ metadata.gz: c71bbd0aa57f772b63a423ce89249f83a97cb0094a9ee4f53fa1088e1ab0a0e87d617f28c574a48af9728d48d97e841d8fbd811a78d9501ed926b1ef59e28457
7
+ data.tar.gz: 022e908a2869b8a01395adf9eba867bd6d3726a28dbfe885b5bd876bad05fda2c9c736c8d6180b685fafabdc075ff6ad2561f63b92a97e633f2c0e900de0f8c0
data/.gitignore CHANGED
@@ -14,3 +14,5 @@ Gemfile.lock
14
14
 
15
15
  # rspec failure tracking
16
16
  .rspec_status
17
+
18
+ .ruby-version
@@ -1,12 +1,17 @@
1
1
  ---
2
2
  language: ruby
3
3
  cache: bundler
4
+ before_install: gem install bundler
4
5
  rvm:
6
+ - 3.0.0
5
7
  - 2.7.2
6
8
  - 2.6.6
7
9
  - 2.5.8
8
10
  gemfile:
9
- - gemfiles/Gemfile.rails_6.1.0
10
- - gemfiles/Gemfile.rails_6.0.3.4
11
- - gemfiles/Gemfile.rails_5.2.4
12
- before_install: gem install bundler -v 2.1.4
11
+ - gemfiles/Gemfile.rails_6.1
12
+ - gemfiles/Gemfile.rails_6.0
13
+ - gemfiles/Gemfile.rails_5.2
14
+ jobs:
15
+ exclude:
16
+ - rvm: 3.0.0
17
+ gemfile: gemfiles/Gemfile.rails_5.2
@@ -30,3 +30,12 @@
30
30
  ## [0.1.5]
31
31
  ### Added
32
32
  - Supported in-memopry fixtures. Now users can dump into and import from in-memory fixture object without saving files.
33
+
34
+ ## [0.2.0]
35
+ ### Added
36
+ - Provide options to limit models to import, so that users can prohibit modification to arbitrary models.
37
+ - Support for Ruby 3.0.0 (requires Rails >= 6.0)
38
+
39
+ ### Changed
40
+ - Accept both global configuration as well as runtime (one-off) settings for all the available options.
41
+ Now all the configured settings will be overridden at runtime when the settings are provided with arguments.
data/README.md CHANGED
@@ -78,24 +78,24 @@ DumpedRailers.import!(fixtures)
78
78
 
79
79
  DumpedRailers does not save the fixtures when `base_dir` keyword argument is not specified.
80
80
 
81
- ### Ignored Columns
81
+ ### Ignoring Certain Columns
82
82
 
83
83
  * By default, DumpedRailers ignore three columns - `id`, `created_at`, `updated_at`. You can always update/change this settings as follows.
84
84
 
85
85
  ```ruby
86
86
  DumpedRailers.configure do |config|
87
- config.ignorable_columns += [:published_on] # published_on will be ignored on top of default settings.
87
+ config.ignorable_columns += [:published_on] # :published_on will be ignored *on top of* default settings.
88
88
  end
89
89
  ```
90
90
 
91
91
  * of course you can totally replace the settings with your own.
92
92
  ```ruby
93
93
  DumpedRailers.configure do |config|
94
- config.ignorable_columns = %i[uuid created_on updated_on] # uuid and created_on will be ignored instead of id, created_at, updated_at
94
+ config.ignorable_columns = %i[uuid created_on updated_on] # :uuid and :created_on will be ignored *instead of* :id, :created_at, :updated_at
95
95
  end
96
96
  ```
97
97
 
98
- ### Masking, filtering
98
+ ### Masking, Filtering
99
99
 
100
100
  * you can pass `preprocessors` to DumpedRailers before it starts dump. All the attributes are filtered through preprocessors in order of registration.
101
101
 
@@ -124,7 +124,38 @@ masking_preprocessor = -> (attrs, model) { attrs.transform_values(&:upcase) }
124
124
 
125
125
  NOTE: The proprocessors must return attributes in the same format `{ attributes_name: value }` so that preprocessors and dump handlers can preprocessors in nested manner.
126
126
 
127
- ### pseudo multi-tenancy (such as ActsAsTenant)
127
+ ### Limiting Import with Authorized Models Only
128
+
129
+ * In case you don't want to accept arbitrary fixtures to import, you can limit model access as follows:
130
+
131
+ ```ruby
132
+ DumpedRailers.import!(fixtures, authorized_models: [Item, Price])
133
+ ```
134
+
135
+ This would allow us to import fixtures for items and prices, but reject modification on User, Purchase, Admin data.
136
+
137
+ NOTE: Only DumpedRailers.import! is affected by this option. DumpedRailers.dump! can't be scoped (at least in the current version).
138
+
139
+ ### Configuration
140
+
141
+ * All the settings can be configured by either configuration (global) or arguments (at runtime).
142
+ * When you have duplicated setting, arguments are respected: you can always override configured settings by arguments.
143
+
144
+ ```ruby
145
+ DumpedRailers.configure do |config|
146
+ config.ignorable_columns = [:archived_at]
147
+ config.preprocessors = [FooPreprocessor, BarPreprocessor]
148
+ end
149
+
150
+ DumpedRailers.dump!(Item, ignorable_columns: [:id], preprocessors: [BazPreprocessor], base_dir: 'tmp/')
151
+ # this would ignore `id` column, and apply BazPreprocessor only
152
+
153
+ DumpedRailers.dump!(Price, base_dir: 'tmp/')
154
+ # this would ignore `archived_at`, applies FooPreprocessor and BazPreprocessor
155
+ # (settings provided with arguments are considered as one-off, and don't survive globally)
156
+ ```
157
+
158
+ ### Dump/Import under default_scope (e.g. ActsAsTenant)
128
159
 
129
160
  * Such library builds multi-tenancy environment on one single database, using default_scope to switch over database access rights between tenants. You can incorporate data from Tenant A to Tenant B as follows. let's say we use [ActsAsTenant](https://github.com/ErwinM/acts_as_tenant)
130
161
 
@@ -27,9 +27,9 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  spec.add_development_dependency 'bundler', '~> 2.0'
29
29
  spec.add_development_dependency 'rake', '~> 12.3.3'
30
- spec.add_development_dependency 'rspec', '~> 3.0'
30
+ spec.add_development_dependency 'rspec', '~> 3.10'
31
31
  spec.add_development_dependency 'sqlite3'
32
- spec.add_development_dependency 'activerecord', '~> 5.2'
32
+ spec.add_development_dependency 'activerecord', '>= 5.2'
33
33
  spec.add_development_dependency 'database_cleaner-active_record', '~> 1.8'
34
34
  spec.add_development_dependency 'pry'
35
35
  spec.add_development_dependency 'pry-byebug'
@@ -1,6 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in dumped_railers.gemspec
4
- gem 'activerecord', '5.2.4'
4
+ gem 'activerecord', '5.2.4.4'
5
5
 
6
6
  gemspec path: '../'
@@ -4,45 +4,50 @@ require 'dumped_railers/version'
4
4
  require 'dumped_railers/file_helper.rb'
5
5
  require 'dumped_railers/dump'
6
6
  require 'dumped_railers/import'
7
+ require 'dumped_railers/configuration'
7
8
 
8
9
  module DumpedRailers
9
- class << self
10
-
11
- def dump!(*models, base_dir: nil, preprocessors: nil)
12
- preprocessors = [Preprocessor::StripIgnorables.new, *preprocessors].compact.uniq
10
+ extend Configuration
13
11
 
14
- fixture_handler = Dump.new(*models, preprocessors: preprocessors)
12
+ class << self
13
+ def dump!(*models, base_dir: nil, preprocessors: nil, ignorable_columns: nil)
14
+ # override global config settings when options are specified
15
+ runtime_options = { preprocessors: preprocessors.presence, ignorable_columns: ignorable_columns.presence }.compact.reverse_merge(dump_options.deep_dup)
16
+ runtime_options[:preprocessors].unshift(
17
+ default_preprocessor(runtime_options[:ignorable_columns])
18
+ )
19
+
20
+ fixture_handler = Dump.new(*models, preprocessors: runtime_options[:preprocessors])
15
21
  fixtures = fixture_handler.build_fixtures!
16
22
  fixture_handler.persist_all!(base_dir)
17
23
 
18
24
  fixtures
19
25
  end
20
26
 
21
- def import!(*paths)
27
+ def import!(*paths, authorized_models: nil)
22
28
  # make sure class-baseed caches starts with clean state
23
29
  DumpedRailers::RecordBuilder::FixtureRow::RecordStore.clear!
24
30
  DumpedRailers::RecordBuilder::DependencyTracker.clear!
25
31
 
26
- fixture_handler = Import.new(*paths)
32
+ # override global config settings when options are specified
33
+ runtime_options = { authorized_models: authorized_models.presence }.compact.reverse_merge(import_options)
34
+
35
+ fixture_handler = Import.new(*paths, authorized_models: runtime_options[:authorized_models])
27
36
  fixture_handler.import_all!
28
37
  end
29
38
 
30
- class Configuration < ::OpenStruct; end
39
+ private
31
40
 
32
- def config
33
- @_config ||= Configuration.new
41
+ def default_preprocessor(ignorable_columns)
42
+ Preprocessor::StripIgnorables.new(*ignorable_columns)
34
43
  end
35
44
 
36
- def configure
37
- yield config
45
+ def dump_options
46
+ options.slice(:ignorable_columns, :preprocessors)
38
47
  end
39
48
 
40
- # FIXME: make it minimum
41
- IGNORABLE_COLUMNS = %w[id created_at updated_at]
42
- def configure_defaults!
43
- configure do |config|
44
- config.ignorable_columns = IGNORABLE_COLUMNS
45
- end
49
+ def import_options
50
+ options.slice(:authorized_models)
46
51
  end
47
52
  end
48
53
 
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DumpedRailers
4
+ module Configuration
5
+ extend Forwardable
6
+ def_delegators :@_config, :preprocessors, :ignorable_columns, :authorized_models
7
+
8
+ def configure
9
+ yield config
10
+ end
11
+
12
+ def options
13
+ config.to_h
14
+ end
15
+
16
+ IGNORABLE_COLUMNS = %w[id created_at updated_at]
17
+ def configure_defaults!
18
+ clear_configuration!(
19
+ ignorable_columns: IGNORABLE_COLUMNS,
20
+ preprocessors: [],
21
+ authorized_models: :any,
22
+ )
23
+ end
24
+
25
+ def config
26
+ @_config ||= OpenStruct.new
27
+ end
28
+ private :config
29
+
30
+ def clear_configuration!(**attrs)
31
+ @_config = OpenStruct.new(attrs)
32
+ end
33
+ private :clear_configuration!
34
+ end
35
+ end
@@ -7,7 +7,7 @@ module DumpedRailers
7
7
  class Dump
8
8
  def initialize(*models, preprocessors: [])
9
9
  @fixture_tables = models.map { |model|
10
- FixtureBuilder::Model.new(model, preprocessors: preprocessors)
10
+ FixtureBuilder::Model.new(model, preprocessors: preprocessors)
11
11
  }
12
12
  end
13
13
 
@@ -6,17 +6,18 @@ module DumpedRailers
6
6
  class Import
7
7
  attr_reader :fixture_set
8
8
 
9
- def initialize(*paths)
9
+ def initialize(*paths, authorized_models: [])
10
10
  if (paths.first.is_a? Hash)
11
11
  @raw_fixtures = paths.first.values
12
12
  else
13
13
  @raw_fixtures = FileHelper.read_fixtures(*paths)
14
14
  end
15
15
 
16
- @fixture_set = RecordBuilder::FixtureSet.new(@raw_fixtures)
16
+ @fixture_set = RecordBuilder::FixtureSet.new(@raw_fixtures, authorized_models: authorized_models)
17
17
  end
18
18
 
19
19
  def import_all!
20
+ fixture_set.authorize_models!
20
21
  fixture_set.sort_by_table_dependencies!
21
22
  @record_sets = fixture_set.build_record_sets!
22
23
 
@@ -3,9 +3,13 @@
3
3
  module DumpedRailers
4
4
  module Preprocessor
5
5
  class StripIgnorables
6
+ def initialize(*ignorable_columns)
7
+ @ignorable_columns = ignorable_columns.compact.map(&:to_s)
8
+ end
9
+
6
10
  def call(attributes, _model)
7
11
  attributes.reject { |column_name, _v|
8
- DumpedRailers.config.ignorable_columns.map(&:to_s).include?(column_name)
12
+ @ignorable_columns.include?(column_name)
9
13
  }
10
14
  end
11
15
  end
@@ -8,35 +8,57 @@ module DumpedRailers
8
8
  class FixtureSet
9
9
  include TSort
10
10
  attr_reader :fixture_tables, :record_sets
11
-
12
- def initialize(raw_fixtures)
11
+
12
+ def initialize(raw_fixtures, authorized_models: [])
13
13
  @fixture_tables = raw_fixtures.map { |raw_records| build_fixture_table(raw_records) }
14
+ @authorized_models = Array(authorized_models)
14
15
  end
15
-
16
+
16
17
  def sort_by_table_dependencies!
17
18
  @fixture_tables.each(&:analyze_metadata_dependencies!)
18
19
  # dependency are sorted in topological order using Active Record reflection
19
20
  @fixture_tables = tsort
20
-
21
+
21
22
  self
22
23
  end
23
-
24
+
25
+ def authorize_models!
26
+ return if @authorized_models.include?(:any)
27
+
28
+ unauthorized_models = fixture_models.reject { |model|
29
+ @authorized_models.include? model
30
+ }
31
+ return if unauthorized_models.empty?
32
+
33
+ raise RuntimeError, <<~"ERROR_MESSAGE"
34
+ You are trying to import data into unauthorized models.
35
+ Make sure that the fixture contains records for authorized models only.
36
+
37
+ Models that are forbidden to access: #{unauthorized_models.map(&:name).join(', ')}
38
+
39
+ ERROR_MESSAGE
40
+ end
41
+
24
42
  def build_record_sets!
25
43
  @record_sets = @fixture_tables.map { |table|
26
44
  [table.model, table.build_records!]
27
45
  }.to_h
28
46
  end
29
-
47
+
30
48
  private
31
-
49
+
32
50
  def build_fixture_table(raw_records)
33
51
  FixtureTable.new(raw_records)
34
52
  end
35
-
53
+
54
+ def fixture_models
55
+ @fixture_tables.map(&:model)
56
+ end
57
+
36
58
  def tsort_each_node(&block)
37
59
  @fixture_tables.each { |table| block.call(table) }
38
60
  end
39
-
61
+
40
62
  def tsort_each_child(node, &block)
41
63
  dependent_nodes = @fixture_tables.select { |table| node.dependencies.include? table.model_name }
42
64
  dependent_nodes.each &block
@@ -1,3 +1,3 @@
1
1
  module DumpedRailers
2
- VERSION = "0.1.5"
2
+ VERSION = '0.2.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dumped_railers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koji Onishi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-18 00:00:00.000000000 Z
11
+ date: 2020-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.0'
47
+ version: '3.10'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.0'
54
+ version: '3.10'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: sqlite3
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -70,14 +70,14 @@ dependencies:
70
70
  name: activerecord
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '5.2'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '5.2'
83
83
  - !ruby/object:Gem::Dependency
@@ -156,10 +156,11 @@ files:
156
156
  - bin/console
157
157
  - bin/setup
158
158
  - dumped_railers.gemspec
159
- - gemfiles/Gemfile.rails_5.2.4
160
- - gemfiles/Gemfile.rails_6.0.3.4
161
- - gemfiles/Gemfile.rails_6.1.0
159
+ - gemfiles/Gemfile.rails_5.2
160
+ - gemfiles/Gemfile.rails_6.0
161
+ - gemfiles/Gemfile.rails_6.1
162
162
  - lib/dumped_railers.rb
163
+ - lib/dumped_railers/configuration.rb
163
164
  - lib/dumped_railers/dump.rb
164
165
  - lib/dumped_railers/file_helper.rb
165
166
  - lib/dumped_railers/fixture_builder/model.rb
@@ -193,7 +194,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
193
194
  - !ruby/object:Gem::Version
194
195
  version: '0'
195
196
  requirements: []
196
- rubygems_version: 3.2.0
197
+ rubygems_version: 3.1.4
197
198
  signing_key:
198
199
  specification_version: 4
199
200
  summary: A flexible fixture importer/exporter, that can transport ActiveRecord data