rom-rails 1.1.0 → 2.3.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 +4 -4
- data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +10 -0
- data/.github/ISSUE_TEMPLATE/---bug-report.md +30 -0
- data/.github/ISSUE_TEMPLATE/---feature-request.md +18 -0
- data/.github/workflows/ci.yml +67 -0
- data/.github/workflows/docsite.yml +34 -0
- data/.github/workflows/sync_configs.yml +30 -0
- data/.rubocop.yml +46 -9
- data/CHANGELOG.md +68 -0
- data/CONTRIBUTING.md +29 -0
- data/Gemfile +21 -12
- data/README.md +3 -5
- data/Rakefile +1 -1
- data/docsite/source/index.html.md +165 -0
- data/lib/generators/rom.rb +8 -0
- data/lib/generators/rom/commands/templates/create.rb.erb +0 -2
- data/lib/generators/rom/commands/templates/delete.rb.erb +0 -1
- data/lib/generators/rom/commands/templates/update.rb.erb +0 -2
- data/lib/generators/rom/commands_generator.rb +1 -1
- data/lib/generators/rom/install/templates/application_model.rb +2 -2
- data/lib/generators/rom/install/templates/initializer.rb.erb +1 -1
- data/lib/generators/rom/install/templates/types.rb +3 -3
- data/lib/generators/rom/install_generator.rb +1 -4
- data/lib/generators/rom/relation_generator.rb +1 -1
- data/lib/generators/rom/repository/templates/repository.rb.erb +8 -0
- data/lib/generators/rom/repository_generator.rb +1 -2
- data/lib/rom/rails/active_record/configuration.rb +41 -55
- data/lib/rom/rails/active_record/uri_builder.rb +70 -0
- data/lib/rom/rails/configuration.rb +1 -1
- data/lib/rom/rails/railtie.rb +30 -12
- data/lib/rom/rails/tasks/db.rake +6 -0
- data/lib/rom/rails/version.rb +1 -1
- data/rom-rails.gemspec +8 -9
- data/spec/dummy/app/commands/create_user.rb +0 -1
- data/spec/dummy/app/forms/user_form.rb +1 -2
- data/spec/dummy/app/relations/dummy_relation.rb +1 -1
- data/spec/dummy/app/relations/tasks.rb +1 -0
- data/spec/dummy/app/relations/users.rb +1 -0
- data/spec/dummy/bin/bundle +1 -1
- data/spec/dummy/bin/rails +1 -1
- data/spec/dummy/config/initializers/rom.rb +4 -3
- data/spec/dummy/lib/additional_app/{app → persistence}/commands/create_additional_task.rb +0 -0
- data/spec/dummy/lib/rom/test_adapter.rb +1 -0
- data/spec/integration/controller_extensions_spec.rb +23 -0
- data/spec/integration/initializer_spec.rb +1 -1
- data/spec/integration/user_commands_spec.rb +1 -1
- data/spec/lib/active_record/configuration_spec.rb +87 -1
- data/spec/lib/generators/commands_generator_spec.rb +2 -3
- data/spec/lib/generators/install_generator_spec.rb +7 -10
- data/spec/lib/generators/mapper_generator_spec.rb +1 -1
- data/spec/lib/generators/relation_generator_spec.rb +5 -2
- data/spec/lib/generators/repository_generator_spec.rb +17 -1
- metadata +45 -34
- data/.travis.yml +0 -20
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module Rails
|
5
|
+
module ActiveRecord
|
6
|
+
class UriBuilder
|
7
|
+
def build(adapter, uri_options)
|
8
|
+
builder_method = :"#{adapter}_uri"
|
9
|
+
|
10
|
+
uri = if respond_to?(builder_method)
|
11
|
+
send(builder_method, uri_options)
|
12
|
+
else
|
13
|
+
generic_uri(uri_options)
|
14
|
+
end
|
15
|
+
|
16
|
+
# JRuby connection strings require special care.
|
17
|
+
if RUBY_ENGINE == 'jruby' && adapter != 'postgresql'
|
18
|
+
uri = "jdbc:#{uri}"
|
19
|
+
end
|
20
|
+
|
21
|
+
uri
|
22
|
+
end
|
23
|
+
|
24
|
+
def sqlite3_uri(config)
|
25
|
+
path = Pathname.new(config.fetch(:root)).join(config.fetch(:database))
|
26
|
+
|
27
|
+
build_uri(
|
28
|
+
scheme: 'sqlite',
|
29
|
+
host: '',
|
30
|
+
path: path.to_s
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def postgresql_uri(config)
|
35
|
+
generic_uri(config.merge(
|
36
|
+
host: config.fetch(:host) { '' },
|
37
|
+
scheme: 'postgres'
|
38
|
+
))
|
39
|
+
end
|
40
|
+
|
41
|
+
def mysql_uri(config)
|
42
|
+
if config.key?(:username) && !config.key?(:password)
|
43
|
+
config.update(password: '')
|
44
|
+
end
|
45
|
+
|
46
|
+
generic_uri(config)
|
47
|
+
end
|
48
|
+
|
49
|
+
def generic_uri(config)
|
50
|
+
build_uri(
|
51
|
+
scheme: config.fetch(:scheme),
|
52
|
+
user: escape_option(config[:username]),
|
53
|
+
password: escape_option(config[:password]),
|
54
|
+
host: config[:host],
|
55
|
+
port: config[:port],
|
56
|
+
path: config[:database]
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
def build_uri(attrs)
|
61
|
+
Addressable::URI.new(attrs).to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
def escape_option(option)
|
65
|
+
option.nil? ? option : CGI.escape(option)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/rom/rails/railtie.rb
CHANGED
@@ -16,20 +16,21 @@ module ROM
|
|
16
16
|
|
17
17
|
# Make `ROM::Rails::Configuration` instance available to the user via
|
18
18
|
# `Rails.application.config` before other initializers run.
|
19
|
-
config.
|
19
|
+
config.before_configuration do |_app|
|
20
20
|
config.rom = Configuration.new
|
21
21
|
end
|
22
22
|
|
23
23
|
initializer 'rom.configure_action_controller' do
|
24
24
|
ActiveSupport.on_load(:action_controller) do
|
25
25
|
ActionController::Base.send(:include, ControllerExtension)
|
26
|
+
ActionController::API.send(:include, ControllerExtension) if defined?(ActionController::API)
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
29
30
|
initializer 'rom.adjust_eager_load_paths' do |app|
|
30
31
|
paths =
|
31
32
|
auto_registration_paths.inject([]) do |result, root_path|
|
32
|
-
result.concat(COMPONENT_DIRS.map { |dir|
|
33
|
+
result.concat(COMPONENT_DIRS.map { |dir| ::Rails.root.join(root_path, dir).to_s })
|
33
34
|
end
|
34
35
|
|
35
36
|
app.config.eager_load_paths -= paths
|
@@ -44,6 +45,10 @@ module ROM
|
|
44
45
|
ROM.env = Railtie.create_container
|
45
46
|
end
|
46
47
|
|
48
|
+
console do |_app|
|
49
|
+
Railtie.configure_console_logger
|
50
|
+
end
|
51
|
+
|
47
52
|
# Behaves like `Railtie#configure` if the given block does not take any
|
48
53
|
# arguments. Otherwise yields the ROM configuration to the block.
|
49
54
|
#
|
@@ -73,7 +78,7 @@ module ROM
|
|
73
78
|
configuration = create_configuration
|
74
79
|
|
75
80
|
auto_registration_paths.each do |root_path|
|
76
|
-
configuration.auto_registration(
|
81
|
+
configuration.auto_registration(::Rails.root.join(root_path), namespace: false)
|
77
82
|
end
|
78
83
|
|
79
84
|
ROM.container(configuration)
|
@@ -81,10 +86,14 @@ module ROM
|
|
81
86
|
|
82
87
|
# @api private
|
83
88
|
def gateways
|
84
|
-
|
89
|
+
if active_record?
|
90
|
+
load_active_record_config.each do |name, spec|
|
91
|
+
config.rom.gateways[name] ||= [:sql, spec[:uri], spec[:options]]
|
92
|
+
end
|
93
|
+
end
|
85
94
|
|
86
95
|
if config.rom.gateways.empty?
|
87
|
-
Rails.logger.warn "It seems that you have not configured any gateways"
|
96
|
+
::Rails.logger.warn "It seems that you have not configured any gateways"
|
88
97
|
|
89
98
|
config.rom.gateways[:default] = [ :memory, "memory://test" ]
|
90
99
|
end
|
@@ -92,13 +101,9 @@ module ROM
|
|
92
101
|
config.rom.gateways
|
93
102
|
end
|
94
103
|
|
95
|
-
#
|
96
|
-
|
97
|
-
|
98
|
-
# @api private
|
99
|
-
def infer_default_gateway
|
100
|
-
spec = ROM::Rails::ActiveRecord::Configuration.call
|
101
|
-
[:sql, spec[:uri], spec[:options]]
|
104
|
+
# Attempt to infer all configured gateways from activerecord
|
105
|
+
def load_active_record_config
|
106
|
+
ROM::Rails::ActiveRecord::Configuration.new.call
|
102
107
|
end
|
103
108
|
|
104
109
|
def load_initializer
|
@@ -129,6 +134,19 @@ module ROM
|
|
129
134
|
def active_record?
|
130
135
|
defined?(::ActiveRecord)
|
131
136
|
end
|
137
|
+
|
138
|
+
# @api private
|
139
|
+
def std_err_out_logger?
|
140
|
+
ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, STDERR, STDOUT)
|
141
|
+
end
|
142
|
+
|
143
|
+
# @api private
|
144
|
+
def configure_console_logger
|
145
|
+
return if active_record? || std_err_out_logger?
|
146
|
+
|
147
|
+
console = ActiveSupport::Logger.new(STDERR)
|
148
|
+
::Rails.logger.extend ActiveSupport::Logger.broadcast console
|
149
|
+
end
|
132
150
|
end
|
133
151
|
end
|
134
152
|
end
|
data/lib/rom/rails/tasks/db.rake
CHANGED
data/lib/rom/rails/version.rb
CHANGED
data/rom-rails.gemspec
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'rom/rails/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
6
|
spec.name = "rom-rails"
|
8
7
|
spec.version = ROM::Rails::VERSION.dup
|
9
|
-
spec.authors = ["Piotr Solnica"]
|
10
|
-
spec.email = ["piotr.solnica@gmail.com"]
|
8
|
+
spec.authors = ["Chris Flipse", "Piotr Solnica"]
|
9
|
+
spec.email = ["cflipse@gmail.com", "piotr.solnica@gmail.com"]
|
11
10
|
spec.summary = 'Integrate Ruby Object Mapper with Rails'
|
12
11
|
spec.homepage = "http://rom-rb.org"
|
13
12
|
spec.license = "MIT"
|
@@ -17,14 +16,14 @@ Gem::Specification.new do |spec|
|
|
17
16
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
17
|
spec.require_paths = ["lib"]
|
19
18
|
|
20
|
-
spec.add_runtime_dependency 'rom', '~> 4.0'
|
21
|
-
spec.add_runtime_dependency 'dry-equalizer', '~> 0.2'
|
22
|
-
spec.add_runtime_dependency 'dry-core', '~> 0.3'
|
23
19
|
spec.add_runtime_dependency 'addressable', '~> 2.3'
|
24
|
-
spec.add_runtime_dependency '
|
20
|
+
spec.add_runtime_dependency 'dry-core', '~> 0.4'
|
21
|
+
spec.add_runtime_dependency 'dry-equalizer', '~> 0.2'
|
22
|
+
spec.add_runtime_dependency 'railties', '>= 3.0', '< 6.2'
|
23
|
+
spec.add_runtime_dependency 'rom', '~> 5.2'
|
25
24
|
|
26
|
-
spec.add_development_dependency "rom-repository"
|
27
25
|
spec.add_development_dependency "bundler"
|
28
26
|
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rom-repository"
|
29
28
|
spec.add_development_dependency "rubocop", "~> 0.50"
|
30
29
|
end
|
data/spec/dummy/bin/bundle
CHANGED
data/spec/dummy/bin/rails
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
ROM::Rails::Railtie.configure do |config|
|
2
2
|
scheme = RUBY_ENGINE == 'jruby' ? 'jdbc:sqlite' : 'sqlite'
|
3
|
-
config.gateways[:
|
4
|
-
config.gateways[:
|
5
|
-
config.
|
3
|
+
config.gateways[:arro] = [:test_adapter, uri: 'http://example.org' ]
|
4
|
+
config.gateways[:sql] = [:sql, "#{scheme}://#{Rails.root}/db/#{Rails.env}.sqlite3"]
|
5
|
+
config.gateways[:default] = [:test_adapter, foo: :bar]
|
6
|
+
config.auto_registration_paths += [Rails.root.join('lib', 'additional_app', 'persistence')]
|
6
7
|
end
|
File without changes
|
@@ -0,0 +1,23 @@
|
|
1
|
+
RSpec.describe "including controller extensions" do
|
2
|
+
describe "An application controller" do
|
3
|
+
let(:controller) do
|
4
|
+
Class.new(ActionController::Base)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "includes the controller extensions" do
|
8
|
+
expect(controller.ancestors).to include(ROM::Rails::ControllerExtension)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
if defined?(ActionController::API)
|
13
|
+
describe "An API controller" do
|
14
|
+
let(:controller) do
|
15
|
+
Class.new(ActionController::API)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "includes the controller extensions" do
|
19
|
+
expect(controller.ancestors).to include(ROM::Rails::ControllerExtension)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -3,7 +3,7 @@ RSpec.describe 'ROM initializer' do
|
|
3
3
|
gateway = ROM::TestAdapter::Gateway.new(foo: :bar)
|
4
4
|
relation = DummyRelation.new([])
|
5
5
|
|
6
|
-
expect(rom.gateways[:
|
6
|
+
expect(rom.gateways[:default]).to eql(gateway)
|
7
7
|
expect(rom.relations.dummy).to eql(relation)
|
8
8
|
end
|
9
9
|
|
@@ -1,15 +1,19 @@
|
|
1
1
|
require 'rom/rails/active_record/configuration'
|
2
|
+
require 'active_record'
|
3
|
+
require 'active_record/database_configurations' if Rails::VERSION::MAJOR >= 6
|
2
4
|
|
3
5
|
RSpec.describe ROM::Rails::ActiveRecord::Configuration do
|
4
6
|
let(:root) { Pathname.new('/path/to/app') }
|
5
7
|
|
8
|
+
subject(:configuration) { described_class.new(root: root) }
|
9
|
+
|
6
10
|
def uri_for(config)
|
7
11
|
result = read(config)
|
8
12
|
result.is_a?(Hash) ? result[:uri] : result
|
9
13
|
end
|
10
14
|
|
11
15
|
def read(config)
|
12
|
-
|
16
|
+
configuration.build(config)
|
13
17
|
end
|
14
18
|
|
15
19
|
def parse(uri)
|
@@ -112,6 +116,88 @@ RSpec.describe ROM::Rails::ActiveRecord::Configuration do
|
|
112
116
|
|
113
117
|
expect(read(config)).to eq uri: expected_uri, options: { pool: 5 }
|
114
118
|
end
|
119
|
+
|
120
|
+
it 'handles special characters in username and password' do
|
121
|
+
config = {
|
122
|
+
pool: 5,
|
123
|
+
adapter: 'mysql2',
|
124
|
+
username: 'r@o%ot',
|
125
|
+
password: 'p@ssw0rd#',
|
126
|
+
database: 'database',
|
127
|
+
host: 'example.com'
|
128
|
+
}
|
129
|
+
|
130
|
+
expected_uri = 'mysql2://r%40o%25ot:p%40ssw0rd%23@example.com/database'
|
131
|
+
expected_uri = "jdbc:#{expected_uri}" if RUBY_ENGINE == 'jruby'
|
132
|
+
|
133
|
+
expect(read(config)).to eq uri: expected_uri, options: { pool: 5 }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
if Rails::VERSION::MAJOR >= 6
|
139
|
+
context "with an activerecord 6 configuration" do
|
140
|
+
subject(:configuration) { described_class.new(root: root, configurations: railsconfig, env: "test") }
|
141
|
+
let(:railsconfig) { ActiveRecord::DatabaseConfigurations.new(config_file) }
|
142
|
+
|
143
|
+
context "with only a single database" do
|
144
|
+
let(:config_file) {
|
145
|
+
{
|
146
|
+
test: {
|
147
|
+
adapter: 'mysql',
|
148
|
+
host: 'example.com',
|
149
|
+
database: 'test',
|
150
|
+
username: 'user',
|
151
|
+
encoding: 'utf8'
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
it "returns the default hash" do
|
157
|
+
expected_uri = uri_for(config_file[:test])
|
158
|
+
expect(configuration.call[:default]).to match(uri: expected_uri, options: { encoding: 'utf8' })
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "with multiple configured databases" do
|
163
|
+
let(:config_file) {
|
164
|
+
{
|
165
|
+
test: {
|
166
|
+
reader: {
|
167
|
+
adapter: 'mysql',
|
168
|
+
host: 'example.com',
|
169
|
+
database: 'test_reader',
|
170
|
+
username: 'user',
|
171
|
+
encoding: 'utf8'
|
172
|
+
},
|
173
|
+
writer: {
|
174
|
+
adapter: 'mysql',
|
175
|
+
host: 'write.example.com',
|
176
|
+
database: 'test_writer',
|
177
|
+
username: 'user',
|
178
|
+
encoding: 'utf8'
|
179
|
+
}
|
180
|
+
}
|
181
|
+
}
|
182
|
+
}
|
183
|
+
|
184
|
+
it "configures the first database as the default" do
|
185
|
+
expected_uri = uri_for(config_file[:test][:reader])
|
186
|
+
expect(configuration.call[:default]).to match(uri: expected_uri, options: {encoding: 'utf8'})
|
187
|
+
end
|
188
|
+
|
189
|
+
it "returns each configured database" do
|
190
|
+
options = { encoding: 'utf8' }
|
191
|
+
expected_reader_uri = uri_for(config_file[:test][:reader])
|
192
|
+
expected_writer_uri = uri_for(config_file[:test][:writer])
|
193
|
+
|
194
|
+
expect(configuration.call).to include(
|
195
|
+
reader: { uri: expected_reader_uri, options: options },
|
196
|
+
writer: { uri: expected_writer_uri, options: options }
|
197
|
+
)
|
198
|
+
end
|
199
|
+
end
|
115
200
|
end
|
201
|
+
|
116
202
|
end
|
117
203
|
end
|