slavery 1.1.1 → 1.2.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 +7 -0
- data/README.md +27 -9
- data/lib/slavery.rb +17 -18
- data/lib/slavery/relation.rb +24 -0
- data/lib/slavery/version.rb +1 -1
- data/spec/slavery_spec.rb +8 -0
- metadata +14 -22
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cf1496eaaf7ad5d9839bf821fc4fafd5b48d2f4c
|
4
|
+
data.tar.gz: 6b3f1389be627e4e46af04b15b31a6efbba80907
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a5c25149caf8f300de53c07e7c2f3892ee1ff1d06972332357fae177a7a407aac2417467e0a60695f03e69552a38c5cd6aeea8670e2003220768770a01a7dd34
|
7
|
+
data.tar.gz: aa386b5a735bd33ff57338e20bcfb0928dc1d8e8aa9092e4452f0f87d8f10e05e522b1dc7f62a94f6345545c308ce18563f89364013bd906bd74a5fadb1f08e6
|
data/README.md
CHANGED
@@ -22,13 +22,9 @@ And create slave configs for each environment.
|
|
22
22
|
|
23
23
|
```yaml
|
24
24
|
development:
|
25
|
-
adapter: mysql2
|
26
|
-
username: root
|
27
25
|
database: myapp_development
|
28
26
|
|
29
27
|
development_slave:
|
30
|
-
adapter: mysql2
|
31
|
-
username: root
|
32
28
|
database: myapp_development
|
33
29
|
```
|
34
30
|
|
@@ -36,7 +32,22 @@ By convention, config keys with `[env]_slave` are automatically used for slave r
|
|
36
32
|
|
37
33
|
Notice that we just copied the settings of `development` to `development_slave`. For `development` and `test`, it's actually recommended as probably you don't want to have replicating multiple databases on your machine. Two connections to the same identical database should be fine for testing purpose.
|
38
34
|
|
39
|
-
|
35
|
+
In case you prefer DRYer definition, YAML's aliasing and key merging might help.
|
36
|
+
|
37
|
+
```yaml
|
38
|
+
common: &common
|
39
|
+
adapter: mysql2
|
40
|
+
username: root
|
41
|
+
database: myapp_development
|
42
|
+
|
43
|
+
development:
|
44
|
+
<<: *common
|
45
|
+
|
46
|
+
development_slave:
|
47
|
+
<<: *common
|
48
|
+
```
|
49
|
+
|
50
|
+
At this point, Slavery does nothing. Run tests and confirm that nothing is broken.
|
40
51
|
|
41
52
|
## Usage
|
42
53
|
|
@@ -58,15 +69,22 @@ Slavery.on_slave do
|
|
58
69
|
end
|
59
70
|
```
|
60
71
|
|
72
|
+
Alternatively, you may call `on_slave` directly on the scope, so that the query will be read from slave when it's executed.
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
User.on_slave.where(active: true).count
|
76
|
+
```
|
77
|
+
|
78
|
+
Caveat: `pluck` is not supported by the scope syntax, you still need `Slavery.on_slave` in this case.
|
79
|
+
|
61
80
|
## Read-only user
|
62
81
|
|
63
82
|
For an extra safeguard, it is recommended to use a read-only user for slave access.
|
64
83
|
|
65
|
-
```
|
84
|
+
```yaml
|
66
85
|
development_slave:
|
67
|
-
|
86
|
+
<<: *common
|
68
87
|
username: readonly
|
69
|
-
database: myapp_development
|
70
88
|
```
|
71
89
|
|
72
90
|
With MySQL, `GRANT SELECT` creates a read-only user.
|
@@ -81,7 +99,7 @@ With this user, writes on slave should raises an exception.
|
|
81
99
|
Slavery.on_slave { User.create } # => ActiveRecord::StatementInvalid: Mysql2::Error: INSERT command denied...
|
82
100
|
```
|
83
101
|
|
84
|
-
It is a good idea to confirm this behavior in your test code.
|
102
|
+
It is a good idea to confirm this behavior in your test code as well.
|
85
103
|
|
86
104
|
## Database failure
|
87
105
|
|
data/lib/slavery.rb
CHANGED
@@ -7,6 +7,8 @@ module Slavery
|
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
9
|
included do
|
10
|
+
require 'slavery/relation'
|
11
|
+
|
10
12
|
class << self
|
11
13
|
alias_method_chain :connection, :slavery
|
12
14
|
end
|
@@ -16,13 +18,21 @@ module Slavery
|
|
16
18
|
|
17
19
|
mattr_accessor :disabled
|
18
20
|
|
19
|
-
|
21
|
+
class << self
|
20
22
|
def on_slave(&block)
|
21
|
-
|
23
|
+
run true, &block
|
22
24
|
end
|
23
25
|
|
24
26
|
def on_master(&block)
|
25
|
-
|
27
|
+
run false, &block
|
28
|
+
end
|
29
|
+
|
30
|
+
def run(new_value)
|
31
|
+
old_value = Thread.current[:on_slave] # Save for recursive nested calls
|
32
|
+
Thread.current[:on_slave] = new_value
|
33
|
+
yield
|
34
|
+
ensure
|
35
|
+
Thread.current[:on_slave] = old_value
|
26
36
|
end
|
27
37
|
|
28
38
|
def env
|
@@ -34,23 +44,12 @@ module Slavery
|
|
34
44
|
@env = ActiveSupport::StringInquirer.new(string)
|
35
45
|
end
|
36
46
|
end
|
37
|
-
extend ModuleFunctions
|
38
47
|
|
39
48
|
module ClassMethods
|
40
|
-
def on_slave
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
def on_master(&block)
|
45
|
-
with_slavery false, &block
|
46
|
-
end
|
47
|
-
|
48
|
-
def with_slavery(new_value)
|
49
|
-
old_value = Thread.current[:on_slave] # Save for recursive nested calls
|
50
|
-
Thread.current[:on_slave] = new_value
|
51
|
-
yield
|
52
|
-
ensure
|
53
|
-
Thread.current[:on_slave] = old_value
|
49
|
+
def on_slave
|
50
|
+
context = scoped
|
51
|
+
context.slavery_target = :slave
|
52
|
+
context
|
54
53
|
end
|
55
54
|
|
56
55
|
def connection_with_slavery
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class ActiveRecord::Relation
|
2
|
+
attr_accessor :slavery_target
|
3
|
+
|
4
|
+
# Supports queries like User.on_slave.all
|
5
|
+
def exec_queries_with_slavery
|
6
|
+
if slavery_target == :slave
|
7
|
+
Slavery.on_slave { exec_queries_without_slavery }
|
8
|
+
else
|
9
|
+
exec_queries_without_slavery
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Supports queries like User.on_slave.count
|
14
|
+
def calculate_with_slavery(operation, column_name, options = {})
|
15
|
+
if slavery_target == :slave
|
16
|
+
Slavery.on_slave { calculate_without_slavery(operation, column_name, options) }
|
17
|
+
else
|
18
|
+
calculate_without_slavery(operation, column_name, options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
alias_method_chain :exec_queries, :slavery
|
23
|
+
alias_method_chain :calculate, :slavery
|
24
|
+
end
|
data/lib/slavery/version.rb
CHANGED
data/spec/slavery_spec.rb
CHANGED
@@ -53,6 +53,14 @@ describe Slavery do
|
|
53
53
|
Slavery.on_slave { User.slaveryable?.should == false }
|
54
54
|
end
|
55
55
|
|
56
|
+
it 'works with scopes' do
|
57
|
+
User.count.should == 2
|
58
|
+
User.on_slave.count.should == 1
|
59
|
+
|
60
|
+
User.scoped.to_a.size.should == 2
|
61
|
+
User.on_slave.scoped.to_a.size.should == 1
|
62
|
+
end
|
63
|
+
|
56
64
|
describe 'configuration' do
|
57
65
|
before do
|
58
66
|
# Backup connection and configs
|
metadata
CHANGED
@@ -1,62 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slavery
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.2.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Kenn Ejima
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2013-05-23 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: activerecord
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: 3.0.0
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 3.0.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rspec
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: sqlite3
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
description: Simple, conservative slave reads for ActiveRecord
|
@@ -74,35 +67,34 @@ files:
|
|
74
67
|
- Rakefile
|
75
68
|
- lib/slavery.rb
|
76
69
|
- lib/slavery/railtie.rb
|
70
|
+
- lib/slavery/relation.rb
|
77
71
|
- lib/slavery/version.rb
|
78
72
|
- slavery.gemspec
|
79
73
|
- spec/slavery_spec.rb
|
80
74
|
- spec/spec_helper.rb
|
81
75
|
homepage: https://github.com/kenn/slavery
|
82
76
|
licenses: []
|
77
|
+
metadata: {}
|
83
78
|
post_install_message:
|
84
79
|
rdoc_options: []
|
85
80
|
require_paths:
|
86
81
|
- lib
|
87
82
|
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
-
none: false
|
89
83
|
requirements:
|
90
|
-
- -
|
84
|
+
- - '>='
|
91
85
|
- !ruby/object:Gem::Version
|
92
86
|
version: '0'
|
93
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
-
none: false
|
95
88
|
requirements:
|
96
|
-
- -
|
89
|
+
- - '>='
|
97
90
|
- !ruby/object:Gem::Version
|
98
91
|
version: '0'
|
99
92
|
requirements: []
|
100
93
|
rubyforge_project:
|
101
|
-
rubygems_version:
|
94
|
+
rubygems_version: 2.0.3
|
102
95
|
signing_key:
|
103
|
-
specification_version:
|
96
|
+
specification_version: 4
|
104
97
|
summary: Simple, conservative slave reads for ActiveRecord
|
105
98
|
test_files:
|
106
99
|
- spec/slavery_spec.rb
|
107
100
|
- spec/spec_helper.rb
|
108
|
-
has_rdoc:
|