db_to_file 1.2.4
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/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +11 -0
- data/db/database.yml +2 -0
- data/db/test.sqlite3 +0 -0
- data/db_to_file.gemspec +33 -0
- data/lib/db_to_file.rb +21 -0
- data/lib/db_to_file/config.rb +56 -0
- data/lib/db_to_file/railtie.rb +12 -0
- data/lib/db_to_file/system_executer.rb +16 -0
- data/lib/db_to_file/unloader.rb +151 -0
- data/lib/db_to_file/uploader.rb +128 -0
- data/lib/db_to_file/values_normalizer/object_to_hash.rb +46 -0
- data/lib/db_to_file/values_normalizer/value_into_object.rb +40 -0
- data/lib/db_to_file/version.rb +3 -0
- data/lib/db_to_file/version_controller.rb +78 -0
- data/lib/tasks/unloader.rake +18 -0
- data/lib/tasks/uploader.rake +37 -0
- data/test/fixtures/config.yml +6 -0
- data/test/lib/db_to_file/unloader_test.rb +137 -0
- data/test/lib/db_to_file/uploader_test.rb +145 -0
- data/test/lib/db_to_file/values_normalizer/object_to_hash_test.rb +68 -0
- data/test/lib/db_to_file/values_normalizer/value_into_object_test.rb +63 -0
- data/test/lib/db_to_file/version_controller_test.rb +132 -0
- data/test/lib/db_to_file/version_test.rb +7 -0
- data/test/lib/setting.rb +3 -0
- data/test/lib/user.rb +2 -0
- data/test/test_helper.rb +45 -0
- metadata +252 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
module DbToFile
|
2
|
+
module ValuesNormalizer
|
3
|
+
class ObjectToHash
|
4
|
+
def initialize(object)
|
5
|
+
@object = object
|
6
|
+
end
|
7
|
+
|
8
|
+
def normalize
|
9
|
+
@hash = {}
|
10
|
+
@object.attributes.each do |field, value|
|
11
|
+
@current_field = field
|
12
|
+
@hash[field] = normalize_field_value(value)
|
13
|
+
end
|
14
|
+
@hash
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def normalize_field_value(value)
|
19
|
+
value = convert_yaml(value)
|
20
|
+
value = convert_nil_value(value)
|
21
|
+
value = convert_integer_to_string(value)
|
22
|
+
value = add_trailing_newline(value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def convert_yaml(value)
|
26
|
+
(!value.nil? && serialized_attribute?(@current_field)) ? value.to_yaml : value
|
27
|
+
end
|
28
|
+
|
29
|
+
def serialized_attribute?(field)
|
30
|
+
@object.class.serialized_attributes.keys.include?(field.to_s)
|
31
|
+
end
|
32
|
+
|
33
|
+
def convert_nil_value(value)
|
34
|
+
(value.nil?) ? '<NULL>' : value
|
35
|
+
end
|
36
|
+
|
37
|
+
def convert_integer_to_string(integer)
|
38
|
+
"#{integer}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_trailing_newline(string)
|
42
|
+
(string[-1] == "\n") ? string : "#{string}\n"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module DbToFile
|
2
|
+
module ValuesNormalizer
|
3
|
+
class ValueIntoObject
|
4
|
+
def initialize(object)
|
5
|
+
@object = object
|
6
|
+
end
|
7
|
+
|
8
|
+
def normalize(fieldname, value)
|
9
|
+
if @object.respond_to?(fieldname.to_sym)
|
10
|
+
normalized_value = normalize_field_value(fieldname, value)
|
11
|
+
@object.send("#{fieldname}=", normalized_value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def normalize_field_value(fieldname, value)
|
17
|
+
@current_field = fieldname
|
18
|
+
value = strip_trailing_newline(value)
|
19
|
+
value = convert_nil_value(value)
|
20
|
+
value = convert_yaml(value)
|
21
|
+
end
|
22
|
+
|
23
|
+
def strip_trailing_newline(text)
|
24
|
+
(text[-1] == "\n") ? text[0..-2] : text
|
25
|
+
end
|
26
|
+
|
27
|
+
def convert_nil_value(value)
|
28
|
+
(value == '<NULL>') ? nil : value
|
29
|
+
end
|
30
|
+
|
31
|
+
def convert_yaml(value)
|
32
|
+
(!value.nil? && serialized_attribute?(@current_field)) ? YAML.load(value) : value
|
33
|
+
end
|
34
|
+
|
35
|
+
def serialized_attribute?(field)
|
36
|
+
@object.class.serialized_attributes.keys.include?(field.to_s)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module DbToFile
|
2
|
+
class VersionController
|
3
|
+
def prepare_code_version
|
4
|
+
SystemExecuter.new("git stash save 'db-to-file'").execute
|
5
|
+
SystemExecuter.new('git pull').execute
|
6
|
+
FileUtils.rm_rf('db/db_to_file')
|
7
|
+
end
|
8
|
+
|
9
|
+
def update_code_version(commit_message = nil)
|
10
|
+
update_commit_stash
|
11
|
+
commit_changes(commit_message) if commitable_files_present?
|
12
|
+
end
|
13
|
+
|
14
|
+
def restore_local_stash
|
15
|
+
restore_stash
|
16
|
+
end
|
17
|
+
|
18
|
+
def merge_conflicts_present?
|
19
|
+
out = SystemExecuter.new('git status --porcelain').execute.split("\n")
|
20
|
+
out.any?{|line| line[0..0] == 'U'}
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_modified_file_list
|
24
|
+
modified_files
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
DEFAULT_COMMIT_MESSAGE = 'DbToFile: changes by customer'
|
29
|
+
|
30
|
+
def update_commit_stash
|
31
|
+
SystemExecuter.new('git status --porcelain').execute
|
32
|
+
new_files.each do |file|
|
33
|
+
SystemExecuter.new("git add #{file}").execute if table_file?(file)
|
34
|
+
end
|
35
|
+
modified_files.each do |file|
|
36
|
+
SystemExecuter.new("git add #{file}").execute if table_file?(file)
|
37
|
+
end
|
38
|
+
deleted_files.each do |file|
|
39
|
+
SystemExecuter.new("git rm #{file}").execute if table_file?(file)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def commitable_files_present?
|
44
|
+
out = SystemExecuter.new('git status --porcelain').execute
|
45
|
+
out.split("\n").reject{|line| [' ', '?'].include?(line[0])}.any?
|
46
|
+
end
|
47
|
+
|
48
|
+
def commit_changes(commit_message)
|
49
|
+
puts 'Commit changes'
|
50
|
+
message = commit_message || DEFAULT_COMMIT_MESSAGE
|
51
|
+
git.commit(message)
|
52
|
+
end
|
53
|
+
|
54
|
+
def restore_stash
|
55
|
+
SystemExecuter.new('git stash pop').execute
|
56
|
+
end
|
57
|
+
|
58
|
+
def new_files
|
59
|
+
git.status.untracked.map{|file, git_object| file}
|
60
|
+
end
|
61
|
+
|
62
|
+
def modified_files
|
63
|
+
git.status.changed.map{|file, git_object| file}
|
64
|
+
end
|
65
|
+
|
66
|
+
def deleted_files
|
67
|
+
git.status.deleted.map{|file, git_object| file}
|
68
|
+
end
|
69
|
+
|
70
|
+
def table_file?(file)
|
71
|
+
file.index('db/db_to_file') === 0
|
72
|
+
end
|
73
|
+
|
74
|
+
def git
|
75
|
+
@git ||= Git.open(Dir.pwd)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
namespace :db_to_file do
|
2
|
+
class WrongEnvironmentGiven < Exception; end
|
3
|
+
|
4
|
+
desc 'Unload tables to file system'
|
5
|
+
task :unload => :environment do |args|
|
6
|
+
# wrong_environment(:environment) unless Rails.env.production?
|
7
|
+
unload_tables
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
def unload_tables
|
12
|
+
DbToFile::Unloader.new.unload
|
13
|
+
end
|
14
|
+
|
15
|
+
def wrong_environment(environment)
|
16
|
+
raise WrongEnvironmentGiven, "Environment should be 'production'. '#{Rails.env}' is used"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
namespace :db_to_file do
|
2
|
+
class NoCommitMessage < Exception; end
|
3
|
+
|
4
|
+
desc "Upload files to the database (set commit message via command 'rake db_to_file:unload['<commit message>'])"
|
5
|
+
task :upload, [:commit_message] => :environment do |t, args|
|
6
|
+
no_commit_message_error if args[:commit_message].blank?
|
7
|
+
|
8
|
+
upload_files(args[:commit_message])
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Force uploading to the database, without checks"
|
12
|
+
task :force_upload => :environment do |t, args|
|
13
|
+
force_upload_files
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Force uploading only changed files in database, without checks'
|
17
|
+
task :force_changed => :environment do |t, args|
|
18
|
+
force_upload_changed_files
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def upload_files(commit_message)
|
23
|
+
DbToFile::Uploader.new.upload(commit_message)
|
24
|
+
end
|
25
|
+
|
26
|
+
def force_upload_files
|
27
|
+
DbToFile::Uploader.new.force_upload
|
28
|
+
end
|
29
|
+
|
30
|
+
def force_upload_changed_files
|
31
|
+
DbToFile::Uploader.new.force_upload
|
32
|
+
end
|
33
|
+
|
34
|
+
def no_commit_message_error
|
35
|
+
raise NoCommitMessage, "invoke via 'rake db_to_file:unload['<commit message>']'"
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe DbToFile::Unloader do
|
5
|
+
let(:unloader) { DbToFile::Unloader.new }
|
6
|
+
|
7
|
+
before do
|
8
|
+
DbToFile::Config.any_instance.stubs(:config_file).returns('test/fixtures/config.yml')
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'configuration-file' do
|
12
|
+
it 'can be parsed' do
|
13
|
+
unloader.send(:tables).must_equal(['users', 'settings'])
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'can read directory prefix' do
|
17
|
+
@table = DbToFile::Unloader::Table.new('users', @unloader)
|
18
|
+
@record = DbToFile::Unloader::Table::Record.new(User.first, @table)
|
19
|
+
|
20
|
+
@record.send(:config_directory_prefix).must_equal('name')
|
21
|
+
|
22
|
+
@table = DbToFile::Unloader::Table.new('settings', @unloader)
|
23
|
+
@record = DbToFile::Unloader::Table::Record.new(Setting.first, @table)
|
24
|
+
|
25
|
+
@record.send(:config_directory_prefix).must_equal(nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'can read file-extensions' do
|
29
|
+
@table = DbToFile::Unloader::Table.new('users', @unloader)
|
30
|
+
@record = DbToFile::Unloader::Table::Record.new(User.first, @table)
|
31
|
+
@field_name = DbToFile::Unloader::Table::Record::Field.new('name', @record)
|
32
|
+
@field_id = DbToFile::Unloader::Table::Record::Field.new('id', @record)
|
33
|
+
|
34
|
+
DbToFile::Config.instance.stub(:config_file, 'test/fixtures/config.yml') do
|
35
|
+
@field_name.send(:config_field_extension).must_equal('txt')
|
36
|
+
@field_id.send(:config_field_extension).must_equal(nil)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'unloading' do
|
42
|
+
it 'calls the functions' do
|
43
|
+
unloader.expects(:prepare_code_version)
|
44
|
+
unloader.expects(:unload_tables)
|
45
|
+
unloader.expects(:update_code_version)
|
46
|
+
unloader.expects(:restore_local_stash)
|
47
|
+
|
48
|
+
unloader.unload
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'build directory for users with prefix' do
|
53
|
+
before do
|
54
|
+
unloader.stubs(:config_directory_prefix).returns('name')
|
55
|
+
DbToFile::Config.instance.stub(:config_file, 'test/fixtures/config.yml') do
|
56
|
+
unloader.stub(:tables, ['users']) do
|
57
|
+
unloader.send(:unload_tables)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
after do
|
63
|
+
FileUtils.rm_rf('db/db_to_file')
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'for the users' do
|
67
|
+
File.directory?('db/db_to_file/users').must_equal true
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'builds the directory for the records' do
|
71
|
+
File.directory?('db/db_to_file/users/ewout-quax_1').must_equal true
|
72
|
+
File.directory?('db/db_to_file/users/test-example_2').must_equal true
|
73
|
+
File.directory?('db/db_to_file/users/3').must_equal true
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'builds the files for the record-files' do
|
77
|
+
File.file?('db/db_to_file/users/ewout-quax_1/id').must_equal true
|
78
|
+
File.file?('db/db_to_file/users/ewout-quax_1/name.txt').must_equal true
|
79
|
+
|
80
|
+
File.read('db/db_to_file/users/ewout-quax_1/name.txt').must_equal "Ewout Quax\n"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'build directory for users without prefix' do
|
85
|
+
before do
|
86
|
+
unloader.stubs(:config_directory_prefix).returns(nil)
|
87
|
+
unloader.stubs(:config_ignore_columns).returns(nil)
|
88
|
+
unloader.stubs(:config_field_extension).returns(nil)
|
89
|
+
unloader.stub(:tables, ['settings']) do
|
90
|
+
unloader.send(:unload_tables)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
after do
|
95
|
+
FileUtils.rm_rf('db/db_to_file')
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'for the settings' do
|
99
|
+
File.directory?('db/db_to_file/settings').must_equal true
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'builds the directory for the records' do
|
103
|
+
File.directory?('db/db_to_file/settings/1').must_equal true
|
104
|
+
File.directory?('db/db_to_file/settings/2').must_equal true
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'builds the files for the record-files' do
|
108
|
+
File.file?('db/db_to_file/settings/2/key').must_equal true
|
109
|
+
File.file?('db/db_to_file/settings/2/value').must_equal true
|
110
|
+
|
111
|
+
File.read('db/db_to_file/settings/2/value').must_equal "<NULL>\n"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe 'prepare code-versioning' do
|
116
|
+
it 'invokes the version-controller' do
|
117
|
+
controller = Minitest::Mock.new
|
118
|
+
DbToFile::VersionController.expects(:new).returns(controller)
|
119
|
+
|
120
|
+
controller.expect(:prepare_code_version, nil)
|
121
|
+
unloader.send(:prepare_code_version)
|
122
|
+
controller.verify
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe 'update_code_version' do
|
127
|
+
it 'invokes all the functions' do
|
128
|
+
controller = Minitest::Mock.new
|
129
|
+
|
130
|
+
unloader.expects(:version_controller).returns(controller)
|
131
|
+
|
132
|
+
controller.expect(:update_code_version, nil)
|
133
|
+
unloader.send(:update_code_version)
|
134
|
+
controller.verify
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe DbToFile::Uploader do
|
5
|
+
it 'invokes all the functions' do
|
6
|
+
uploader = DbToFile::Uploader.new
|
7
|
+
|
8
|
+
uploader.expects(:can_continue?).returns(true).times(2)
|
9
|
+
uploader.expects(:invoke_unloader)
|
10
|
+
uploader.expects(:write_objects_to_db)
|
11
|
+
uploader.expects(:update_code_version)
|
12
|
+
|
13
|
+
uploader.upload('uploader_test')
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'can_continue' do
|
17
|
+
let(:uploader) { DbToFile::Uploader.new }
|
18
|
+
|
19
|
+
it 'return false, if merge conflicts are found' do
|
20
|
+
uploader.stub(:merge_conflicts_present?, true) do
|
21
|
+
uploader.send(:can_continue?).must_equal(false)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'return true, if no merge conflicts are found' do
|
26
|
+
uploader.stub(:merge_conflicts_present?, false) do
|
27
|
+
uploader.send(:can_continue?).must_equal(true)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'merge_conflicts_present' do
|
33
|
+
let(:uploader) { DbToFile::Uploader.new }
|
34
|
+
let(:controller) { Minitest::Mock.new }
|
35
|
+
|
36
|
+
it 'invokes the version controller' do
|
37
|
+
controller.expect(:merge_conflicts_present?, true)
|
38
|
+
uploader.stub(:version_controller, controller) do
|
39
|
+
uploader.send(:merge_conflicts_present?).must_equal(true)
|
40
|
+
end
|
41
|
+
controller.verify
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'objects' do
|
46
|
+
after do
|
47
|
+
User.last.delete
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'are saved to the db' do
|
51
|
+
user_1 = User.new(name: 'Test UserName')
|
52
|
+
uploader = DbToFile::Uploader.new
|
53
|
+
uploader.expects(:build_objects).returns([user_1])
|
54
|
+
|
55
|
+
uploader.send(:write_objects_to_db)
|
56
|
+
|
57
|
+
User.last.must_equal(user_1)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'unloaded files' do
|
62
|
+
before do
|
63
|
+
write_file('db/db_to_file/users/ewout-quax_1', 'id', '1')
|
64
|
+
write_file('db/db_to_file/users/ewout-quax_1', 'name.txt', 'Ewout Quax')
|
65
|
+
write_file('db/db_to_file/users/test-example_2', 'id', '2')
|
66
|
+
write_file('db/db_to_file/users/test-example_2', 'name.txt', 'Test Example')
|
67
|
+
end
|
68
|
+
|
69
|
+
after do
|
70
|
+
FileUtils.rm_rf('db/db_to_file')
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'can be read' do
|
74
|
+
files = DbToFile::Uploader.new.send(:read_files)
|
75
|
+
files.include?('db/db_to_file/users/ewout-quax_1/id').must_equal true
|
76
|
+
files.include?('db/db_to_file/users/ewout-quax_1/name.txt').must_equal true
|
77
|
+
files.include?('db/db_to_file/users/test-example_2/id').must_equal true
|
78
|
+
files.include?('db/db_to_file/users/test-example_2/name.txt').must_equal true
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'can be builded into models' do
|
82
|
+
models = DbToFile::Uploader.new.send(:build_objects)
|
83
|
+
models.size.must_equal 2
|
84
|
+
models.first.class.must_equal(User)
|
85
|
+
models.last.class.must_equal(User)
|
86
|
+
|
87
|
+
user_1 = models.detect{|m| m.id == 1}
|
88
|
+
user_2 = models.detect{|m| m.id == 2}
|
89
|
+
user_1.name.must_equal 'Ewout Quax'
|
90
|
+
user_2.name.must_equal 'Test Example'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'update_code_version' do
|
95
|
+
let(:uploader) { DbToFile::Uploader.new }
|
96
|
+
let(:controller) { Minitest::Mock.new }
|
97
|
+
|
98
|
+
it 'invokes the version-controller, with a commit message' do
|
99
|
+
uploader.expects(:version_controller).returns(controller)
|
100
|
+
|
101
|
+
controller.expect(:update_code_version, true, ['commit via test'])
|
102
|
+
uploader.send(:update_code_version, 'commit via test')
|
103
|
+
controller.verify
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe 'update_object_with_field_value' do
|
108
|
+
let(:uploader) { DbToFile::Uploader.new }
|
109
|
+
|
110
|
+
it 'with field value' do
|
111
|
+
uploader.expects(:file_value).with('db/db_to_file/users/1/name').returns('Bruce Wayne')
|
112
|
+
|
113
|
+
object = User.new
|
114
|
+
uploader.send(:update_object_with_field_value, object, 'name', 'db/db_to_file/users/1/name')
|
115
|
+
object.name.must_equal('Bruce Wayne')
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'strips newline at end of field-value' do
|
119
|
+
uploader.expects(:file_value).with('db/db_to_file/users/1/name').returns("Bruce Wayne\n")
|
120
|
+
|
121
|
+
object = User.new
|
122
|
+
uploader.send(:update_object_with_field_value, object, 'name', 'db/db_to_file/users/1/name')
|
123
|
+
object.name.must_equal('Bruce Wayne')
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'converts <NULL> to nil-value' do
|
127
|
+
uploader.expects(:file_value).with('db/db_to_file/users/1/name').returns("<NULL>\n")
|
128
|
+
|
129
|
+
object = User.new
|
130
|
+
uploader.send(:update_object_with_field_value, object, 'name', 'db/db_to_file/users/1/name')
|
131
|
+
object.name.must_equal(nil)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe 'extract_data_segments' do
|
136
|
+
it 'splits the full-file-path into segments' do
|
137
|
+
uploader = DbToFile::Uploader.new
|
138
|
+
segments = uploader.send(:extract_data_segments, '/db/db_to_files/users/ewout-quax_1/name.txt')
|
139
|
+
|
140
|
+
segments[:model].must_equal User
|
141
|
+
segments[:id].must_equal 1
|
142
|
+
segments[:field].must_equal 'name'
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|