slavery 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|