command_model 2.0.0 → 2.1.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/workflows/ci.yml +26 -0
- data/.gitignore +1 -1
- data/.ruby-version +1 -0
- data/.tool-versions +1 -0
- data/Gemfile.lock +50 -0
- data/README.md +135 -54
- data/Rakefile +4 -7
- data/bin/rake +27 -0
- data/command_model.gemspec +4 -5
- data/examples/bank/Gemfile +4 -4
- data/examples/bank/app/controllers/accounts_controller.rb +12 -12
- data/examples/bank/app/controllers/transfers_controller.rb +3 -3
- data/examples/bank/app/views/accounts/deposit_form.html.erb +1 -5
- data/examples/bank/app/views/accounts/withdraw_form.html.erb +1 -5
- data/examples/bank/app/views/layouts/application.html.erb +1 -1
- data/examples/bank/app/views/transfers/new.html.erb +2 -6
- data/examples/bank/config/application.rb +1 -1
- data/examples/bank/config/routes.rb +6 -6
- data/examples/bank/test/performance/browsing_test.rb +2 -2
- data/gemfiles/{5.0.gemfile → 6.1.gemfile} +1 -1
- data/gemfiles/6.1.gemfile.lock +52 -0
- data/gemfiles/{5.1.gemfile → 7.0.gemfile} +1 -1
- data/gemfiles/7.0.gemfile.lock +50 -0
- data/gemfiles/7.1.gemfile +5 -0
- data/gemfiles/7.1.gemfile.lock +60 -0
- data/lib/command_model/convert.rb +1 -1
- data/lib/command_model/model.rb +61 -16
- data/lib/command_model/version.rb +1 -1
- data/spec/convert_spec.rb +5 -4
- data/spec/model_spec.rb +129 -6
- metadata +24 -17
- data/.travis.yml +0 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ae545ab3c7c527111971b821772770a8b050f897550fa3512c6476edd67182d1
|
|
4
|
+
data.tar.gz: be5789d54e5e90730445343e9d29bd789c6a3f5f42e34a5f78075996ae51d929
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 02613c5fed0d0518ac3bff0a2d7b0fc77974d323693e1f18068d767c28bc4cc7521bb7fdece9a49ef5ef8c82a4213c098edb61972a391cb6b2be90570efc349c
|
|
7
|
+
data.tar.gz: d683d0d3823c268784c1821c9defed0f68fb3cc7c5cda98440d2676bae7845d8b2e6aa94de6f5ce3665b9235f7bd25efe1ec51b312342441efec370feb9d2ea9
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: "Ruby CI"
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: ["master"]
|
|
5
|
+
pull_request:
|
|
6
|
+
branches: ["master"]
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
strategy:
|
|
10
|
+
fail-fast: false
|
|
11
|
+
matrix:
|
|
12
|
+
ruby: ['3.2', '3.3']
|
|
13
|
+
gemfile: [ "6.1", "7.0", "7.1" ]
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
env:
|
|
16
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout code
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
- name: Install Ruby and gems
|
|
21
|
+
uses: ruby/setup-ruby@v1
|
|
22
|
+
with:
|
|
23
|
+
ruby-version: ${{ matrix.ruby }}
|
|
24
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
25
|
+
- name: Run tests
|
|
26
|
+
run: bin/rake
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.2.2
|
data/.tool-versions
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ruby 3.2.2
|
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
command_model (2.1.0)
|
|
5
|
+
activemodel (> 6.1)
|
|
6
|
+
|
|
7
|
+
GEM
|
|
8
|
+
remote: https://rubygems.org/
|
|
9
|
+
specs:
|
|
10
|
+
activemodel (7.0.4.3)
|
|
11
|
+
activesupport (= 7.0.4.3)
|
|
12
|
+
activesupport (7.0.4.3)
|
|
13
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
14
|
+
i18n (>= 1.6, < 2)
|
|
15
|
+
minitest (>= 5.1)
|
|
16
|
+
tzinfo (~> 2.0)
|
|
17
|
+
concurrent-ruby (1.2.2)
|
|
18
|
+
diff-lcs (1.5.1)
|
|
19
|
+
i18n (1.12.0)
|
|
20
|
+
concurrent-ruby (~> 1.0)
|
|
21
|
+
minitest (5.18.0)
|
|
22
|
+
rake (13.1.0)
|
|
23
|
+
rspec (3.13.0)
|
|
24
|
+
rspec-core (~> 3.13.0)
|
|
25
|
+
rspec-expectations (~> 3.13.0)
|
|
26
|
+
rspec-mocks (~> 3.13.0)
|
|
27
|
+
rspec-core (3.13.0)
|
|
28
|
+
rspec-support (~> 3.13.0)
|
|
29
|
+
rspec-expectations (3.13.0)
|
|
30
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
31
|
+
rspec-support (~> 3.13.0)
|
|
32
|
+
rspec-mocks (3.13.0)
|
|
33
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
34
|
+
rspec-support (~> 3.13.0)
|
|
35
|
+
rspec-support (3.13.1)
|
|
36
|
+
tzinfo (2.0.6)
|
|
37
|
+
concurrent-ruby (~> 1.0)
|
|
38
|
+
|
|
39
|
+
PLATFORMS
|
|
40
|
+
arm64-darwin-22
|
|
41
|
+
arm64-darwin-23
|
|
42
|
+
x86_64-linux
|
|
43
|
+
|
|
44
|
+
DEPENDENCIES
|
|
45
|
+
command_model!
|
|
46
|
+
rake (~> 13.1.0)
|
|
47
|
+
rspec (~> 3.13.0)
|
|
48
|
+
|
|
49
|
+
BUNDLED WITH
|
|
50
|
+
2.4.3
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://github.com/jackc/command_model/actions/workflows/ci.yml)
|
|
2
2
|
|
|
3
3
|
# CommandModel
|
|
4
4
|
|
|
@@ -14,11 +14,13 @@ to work with once your domain operations become more complex. Domain models
|
|
|
14
14
|
usually have richer behavior than can be represented with a typical
|
|
15
15
|
ActiveRecord style update_attributes.
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
```ruby
|
|
18
|
+
# yuck!
|
|
19
|
+
account.update_attributes balance: account.balance - 50
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
# much better
|
|
22
|
+
account.withdraw amount: 50
|
|
23
|
+
```
|
|
22
24
|
|
|
23
25
|
But there are multiple complications with the OO approach. How do we integrate
|
|
24
26
|
Rails style validations? How are user-supplied strings type converted? How do we
|
|
@@ -28,27 +30,35 @@ know if the command succeeded? CommandModel solves these problems.
|
|
|
28
30
|
|
|
29
31
|
Add this line to your application's Gemfile:
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
```ruby
|
|
34
|
+
gem 'command_model'
|
|
35
|
+
```
|
|
32
36
|
|
|
33
37
|
And then execute:
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
```console
|
|
40
|
+
$ bundle
|
|
41
|
+
```
|
|
36
42
|
|
|
37
43
|
Or install it yourself as:
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
```console
|
|
46
|
+
$ gem install command_model
|
|
47
|
+
```
|
|
40
48
|
|
|
41
49
|
## Usage
|
|
42
50
|
|
|
43
51
|
Create a class derived from CommandModel::Model to represent the command
|
|
44
52
|
request.
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
```ruby
|
|
55
|
+
class WithdrawCommand < CommandModel::Model
|
|
56
|
+
parameter :amount,
|
|
57
|
+
convert: :integer,
|
|
58
|
+
presence: true,
|
|
59
|
+
numericality: { greater_than: 0, less_than_or_equal_to: 500 }
|
|
60
|
+
end
|
|
61
|
+
```
|
|
52
62
|
|
|
53
63
|
Create the method to run the command. This method should instantiate and call a new command object. It must pass call
|
|
54
64
|
a block that actually does the work. The block will only be called if
|
|
@@ -57,32 +67,36 @@ any further validations that only can be done during execution. If it adds
|
|
|
57
67
|
any errors to the command object then the command will be considered to have
|
|
58
68
|
failed. Finally, the call method will return self.
|
|
59
69
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def withdraw(args)
|
|
64
|
-
WithdrawCommand.new(args).call do |command|
|
|
65
|
-
if balance >= command.amount
|
|
66
|
-
@balance -= command.amount
|
|
67
|
-
else
|
|
68
|
-
command.errors.add :amount, "is more than account balance"
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
70
|
+
```ruby
|
|
71
|
+
class Account
|
|
72
|
+
# ...
|
|
72
73
|
|
|
73
|
-
|
|
74
|
+
def withdraw(args)
|
|
75
|
+
WithdrawCommand.new(args).call do |command|
|
|
76
|
+
if balance >= command.amount
|
|
77
|
+
@balance -= command.amount
|
|
78
|
+
else
|
|
79
|
+
command.errors.add :amount, "is more than account balance"
|
|
80
|
+
end
|
|
74
81
|
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# ...
|
|
85
|
+
end
|
|
86
|
+
```
|
|
75
87
|
|
|
76
88
|
Use example:
|
|
77
89
|
|
|
78
|
-
|
|
90
|
+
```ruby
|
|
91
|
+
response = account.withdraw amount: 50
|
|
79
92
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
93
|
+
if response.success?
|
|
94
|
+
puts "Success!"
|
|
95
|
+
else
|
|
96
|
+
puts "Errors:"
|
|
97
|
+
puts response.errors.full_messages
|
|
98
|
+
end
|
|
99
|
+
```
|
|
86
100
|
|
|
87
101
|
## Mixing in Domain Logic
|
|
88
102
|
|
|
@@ -93,28 +107,73 @@ method. The execute method is called by the call method if all validations
|
|
|
93
107
|
succeed. The following is a reimplementation of the previous example with
|
|
94
108
|
internal domain logic.
|
|
95
109
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
110
|
+
```ruby
|
|
111
|
+
class WithdrawCommand < CommandModel::Model
|
|
112
|
+
parameter :amount,
|
|
113
|
+
convert: :integer,
|
|
114
|
+
presence: true,
|
|
115
|
+
numericality: { greater_than: 0, less_than_or_equal_to: 500 }
|
|
116
|
+
parameter :account_id, presence: true
|
|
117
|
+
|
|
118
|
+
def execute
|
|
119
|
+
account = Account.find_by_id account_id
|
|
120
|
+
unless account
|
|
121
|
+
errors.add :account_id, "not found"
|
|
122
|
+
return
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
if account.balance >= amount
|
|
126
|
+
account.balance -= amount
|
|
127
|
+
else
|
|
128
|
+
errors.add :amount, "is more than account balance"
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Dependencies
|
|
135
|
+
|
|
136
|
+
Sometimes a command has requires values that are not supplied by the user. For example, a command may require the
|
|
137
|
+
current user, a database connection, or a logger. These dependencies can be specified with the `dependency` method. The following example adds filtering to ensure that the current user owns the account.
|
|
138
|
+
|
|
139
|
+
```ruby
|
|
140
|
+
class WithdrawCommand < CommandModel::Model
|
|
141
|
+
dependency :current_user
|
|
142
|
+
|
|
143
|
+
parameter :amount,
|
|
144
|
+
convert: :integer,
|
|
145
|
+
presence: true,
|
|
146
|
+
numericality: { greater_than: 0, less_than_or_equal_to: 500 }
|
|
147
|
+
parameter :account_id, presence: true
|
|
148
|
+
|
|
149
|
+
def execute
|
|
150
|
+
account = current_user.accounts.find_by_id account_id
|
|
151
|
+
unless account
|
|
152
|
+
errors.add :account_id, "not found"
|
|
153
|
+
return
|
|
116
154
|
end
|
|
117
155
|
|
|
156
|
+
if account.balance >= amount
|
|
157
|
+
account.balance -= amount
|
|
158
|
+
else
|
|
159
|
+
errors.add :amount, "is more than account balance"
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
This command could be called as follows.
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
WithdrawCommand.execute({amount: 200}, {current_user: current_user})
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Inheritance
|
|
172
|
+
|
|
173
|
+
Subclasses of `CommandModel::Model` can themselves be subclassed. Parameter and dependency definitions will be copied at
|
|
174
|
+
the time of subclassing. If the superclass is later modified, the parameter and dependency definitions of the subclasses
|
|
175
|
+
will not be modified. This may be changed in the future.
|
|
176
|
+
|
|
118
177
|
## Other uses
|
|
119
178
|
|
|
120
179
|
This could be used to wrap database generated errors into normal Rails
|
|
@@ -128,8 +187,30 @@ be doing a uniqueness check anyway.
|
|
|
128
187
|
There is a simple Rails application in examples/bank that demonstrates the
|
|
129
188
|
integration of Rails form helpers and validations with CommandModel.
|
|
130
189
|
|
|
190
|
+
## Testing
|
|
191
|
+
|
|
192
|
+
```console
|
|
193
|
+
$ bundle install
|
|
194
|
+
$ rake
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
To test against a specific version of Rails / ActiveModel set the BUNDLE_GEMFILE environment variable. For example, to
|
|
198
|
+
test Rails 6.1:
|
|
199
|
+
|
|
200
|
+
```console
|
|
201
|
+
$ BUNDLE_GEMFILE=gemfiles/6.1.gemfile bundle install
|
|
202
|
+
$ BUNDLE_GEMFILE=gemfiles/6.1.gemfile rake
|
|
203
|
+
```
|
|
204
|
+
|
|
131
205
|
## Version History
|
|
132
206
|
|
|
207
|
+
* 2.1.0 - March 15, 2023
|
|
208
|
+
* Add dependencies to CommandModel::Model
|
|
209
|
+
* Allow inheritance of CommandModel::Model
|
|
210
|
+
* Require Ruby 3.2+
|
|
211
|
+
* Require Rails / ActiveModel 6.1+
|
|
212
|
+
* 2.0.1 - April 3, 2023
|
|
213
|
+
* Date parsing allows 5 digit years
|
|
133
214
|
* 2.0 - April 11, 2018
|
|
134
215
|
* Rename typecast parameter option to convert
|
|
135
216
|
* Any callable object can be used as a type converter
|
data/Rakefile
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
require "bundler/setup"
|
|
2
2
|
require "bundler/gem_tasks"
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
RSpec::Core::RakeTask.new(:spec)
|
|
7
|
-
rescue LoadError
|
|
8
|
-
end
|
|
4
|
+
require 'rspec/core/rake_task'
|
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
9
6
|
|
|
10
|
-
task :
|
|
7
|
+
task default: :spec
|
data/bin/rake
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("rake", "rake")
|
data/command_model.gemspec
CHANGED
|
@@ -9,16 +9,15 @@ Gem::Specification.new do |gem|
|
|
|
9
9
|
gem.homepage = "https://github.com/JackC/command_model"
|
|
10
10
|
|
|
11
11
|
gem.files = `git ls-files`.split($\)
|
|
12
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
|
13
12
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
14
13
|
gem.name = "command_model"
|
|
15
14
|
gem.require_paths = ["lib"]
|
|
16
15
|
gem.version = CommandModel::VERSION
|
|
17
16
|
|
|
18
|
-
gem.required_ruby_version = '>= 2.
|
|
17
|
+
gem.required_ruby_version = '>= 3.2.0'
|
|
19
18
|
|
|
20
|
-
gem.add_dependency 'activemodel', ">
|
|
19
|
+
gem.add_dependency 'activemodel', "> 6.1"
|
|
21
20
|
|
|
22
|
-
gem.add_development_dependency 'rake', "~>
|
|
23
|
-
gem.add_development_dependency 'rspec', "~> 3.
|
|
21
|
+
gem.add_development_dependency 'rake', "~> 13.1.0"
|
|
22
|
+
gem.add_development_dependency 'rspec', "~> 3.13.0"
|
|
24
23
|
end
|
data/examples/bank/Gemfile
CHANGED
|
@@ -3,9 +3,9 @@ source 'https://rubygems.org'
|
|
|
3
3
|
gem 'rails', '3.2.8'
|
|
4
4
|
|
|
5
5
|
# Bundle edge Rails instead:
|
|
6
|
-
# gem 'rails', :
|
|
6
|
+
# gem 'rails', git: 'git://github.com/rails/rails.git'
|
|
7
7
|
|
|
8
|
-
gem 'command_model', :
|
|
8
|
+
gem 'command_model', path: '../..'
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
# Gems used only for assets and not required
|
|
@@ -15,7 +15,7 @@ group :assets do
|
|
|
15
15
|
gem 'coffee-rails', '~> 3.2.1'
|
|
16
16
|
|
|
17
17
|
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
|
|
18
|
-
# gem 'therubyracer', :
|
|
18
|
+
# gem 'therubyracer', platform: :ruby
|
|
19
19
|
|
|
20
20
|
gem 'uglifier', '>= 1.0.3'
|
|
21
21
|
end
|
|
@@ -35,4 +35,4 @@ gem 'jquery-rails'
|
|
|
35
35
|
# gem 'capistrano'
|
|
36
36
|
|
|
37
37
|
# To use debugger
|
|
38
|
-
# gem 'ruby-debug19', :
|
|
38
|
+
# gem 'ruby-debug19', require: 'ruby-debug'
|
|
@@ -7,44 +7,44 @@
|
|
|
7
7
|
@account = Account.find_by_name params[:id]
|
|
8
8
|
@deposit = Account::DepositCommand.new
|
|
9
9
|
end
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
def deposit
|
|
12
12
|
@account = Account.find_by_name params[:id]
|
|
13
13
|
@deposit = @account.deposit params[:deposit]
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
if @deposit.success?
|
|
16
|
-
redirect_to root_path, :
|
|
16
|
+
redirect_to root_path, notice: "Deposited #{@deposit.amount} to #{@account.name}'s account."
|
|
17
17
|
else
|
|
18
18
|
render "deposit_form"
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
def withdraw_form
|
|
23
23
|
@account = Account.find_by_name params[:id]
|
|
24
24
|
@withdraw = Account::WithdrawCommand.new
|
|
25
|
-
end
|
|
26
|
-
|
|
25
|
+
end
|
|
26
|
+
|
|
27
27
|
def withdraw
|
|
28
28
|
@account = Account.find_by_name params[:id]
|
|
29
29
|
@withdraw = @account.withdraw params[:withdraw]
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
if @withdraw.success?
|
|
32
|
-
redirect_to root_path, :
|
|
32
|
+
redirect_to root_path, notice: "Withdrew #{@withdraw.amount} from #{@account.name}'s account."
|
|
33
33
|
else
|
|
34
34
|
render "withdraw_form"
|
|
35
|
-
end
|
|
35
|
+
end
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def transfer_form
|
|
39
39
|
@accounts = Account.all
|
|
40
40
|
@transfer = Account::TransferCommand.new
|
|
41
41
|
end
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
def transfer
|
|
44
44
|
@transfer = Account::TransferCommand.new(params[:transfer])
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
if @transfer.call.success?
|
|
47
|
-
redirect_to root_path, :
|
|
47
|
+
redirect_to root_path, notice: "Transferred #{@transfer.amount} from #{@transfer.from.name}'s account to #{@transfer.to.name}'s account."
|
|
48
48
|
else
|
|
49
49
|
@accounts = Account.all
|
|
50
50
|
render "transfer_form"
|
|
@@ -3,12 +3,12 @@ class TransfersController < ApplicationController
|
|
|
3
3
|
@accounts = Account.all
|
|
4
4
|
@transfer = Account::Transfer.new
|
|
5
5
|
end
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
def create
|
|
8
8
|
@transfer = Account::Transfer.new(params[:transfer])
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
if @transfer.call.success?
|
|
11
|
-
redirect_to root_path, :
|
|
11
|
+
redirect_to root_path, notice: "Transferred #{@transfer.amount} from #{@transfer.from.name}'s account to #{@transfer.to.name}'s account."
|
|
12
12
|
else
|
|
13
13
|
@accounts = Account.all
|
|
14
14
|
render :new
|
|
@@ -12,12 +12,8 @@
|
|
|
12
12
|
</ul>
|
|
13
13
|
<% end %>
|
|
14
14
|
|
|
15
|
-
<%= form_for @deposit, :
|
|
15
|
+
<%= form_for @deposit, as: :deposit, url: account_deposit_path(@account) do |f| %>
|
|
16
16
|
<%= f.label :amount %>
|
|
17
17
|
<%= f.text_field :amount %>
|
|
18
18
|
<%= f.submit "Deposit" %>
|
|
19
19
|
<% end %>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
@@ -12,12 +12,8 @@
|
|
|
12
12
|
</ul>
|
|
13
13
|
<% end %>
|
|
14
14
|
|
|
15
|
-
<%= form_for @withdraw, :
|
|
15
|
+
<%= form_for @withdraw, as: :withdraw, url: account_withdraw_path(@account) do |f| %>
|
|
16
16
|
<%= f.label :amount %>
|
|
17
17
|
<%= f.text_field :amount %>
|
|
18
18
|
<%= f.submit "Deposit" %>
|
|
19
19
|
<% end %>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
<%= form_for @transfer do |f| %>
|
|
15
15
|
<div>
|
|
16
16
|
<%= f.label :from_name %><br />
|
|
17
|
-
<%= f.select :from_name, @accounts.map { |a| ["#{a.name} - #{a.balance}", a.name] }, :
|
|
17
|
+
<%= f.select :from_name, @accounts.map { |a| ["#{a.name} - #{a.balance}", a.name] }, selected: f.object.from_name, include_blank: true %>
|
|
18
18
|
</div>
|
|
19
19
|
<div>
|
|
20
20
|
<%= f.label :to_name %><br />
|
|
21
|
-
<%= f.select :to_name, @accounts.map { |a| ["#{a.name} - #{a.balance}", a.name] }, :
|
|
21
|
+
<%= f.select :to_name, @accounts.map { |a| ["#{a.name} - #{a.balance}", a.name] }, selected: f.object.to_name, include_blank: true %>
|
|
22
22
|
</div>
|
|
23
23
|
<div>
|
|
24
24
|
<%= f.label :amount %><br />
|
|
@@ -26,7 +26,3 @@
|
|
|
26
26
|
</div>
|
|
27
27
|
<%= f.submit "Transfer" %>
|
|
28
28
|
<% end %>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
@@ -10,7 +10,7 @@ require "rails/test_unit/railtie"
|
|
|
10
10
|
|
|
11
11
|
if defined?(Bundler)
|
|
12
12
|
# If you precompile assets before deploying to production, use this line
|
|
13
|
-
Bundler.require(*Rails.groups(:
|
|
13
|
+
Bundler.require(*Rails.groups(assets: %w(development test)))
|
|
14
14
|
# If you want your assets lazily compiled in production, use this line
|
|
15
15
|
# Bundler.require(:default, :assets, Rails.env)
|
|
16
16
|
end
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Bank::Application.routes.draw do
|
|
2
|
-
get "accounts/:id/withdraw" => "accounts#withdraw_form", :
|
|
3
|
-
post "accounts/:id/withdraw" => "accounts#withdraw", :
|
|
4
|
-
|
|
5
|
-
get "accounts/:id/deposit" => "accounts#deposit_form", :
|
|
6
|
-
post "accounts/:id/deposit" => "accounts#deposit", :
|
|
2
|
+
get "accounts/:id/withdraw" => "accounts#withdraw_form", as: :account_withdraw_form
|
|
3
|
+
post "accounts/:id/withdraw" => "accounts#withdraw", as: :account_withdraw
|
|
4
|
+
|
|
5
|
+
get "accounts/:id/deposit" => "accounts#deposit_form", as: :account_deposit_form
|
|
6
|
+
post "accounts/:id/deposit" => "accounts#deposit", as: :account_deposit
|
|
7
7
|
|
|
8
8
|
resources :transfers, only: %w[new create]
|
|
9
9
|
|
|
10
|
-
root :
|
|
10
|
+
root to: "accounts#index"
|
|
11
11
|
end
|
|
@@ -3,8 +3,8 @@ require 'rails/performance_test_help'
|
|
|
3
3
|
|
|
4
4
|
class BrowsingTest < ActionDispatch::PerformanceTest
|
|
5
5
|
# Refer to the documentation for all available options
|
|
6
|
-
# self.profile_options = { :
|
|
7
|
-
# :
|
|
6
|
+
# self.profile_options = { runs: 5, metrics: [:wall_time, :memory]
|
|
7
|
+
# output: 'tmp/performance', formats: [:flat] }
|
|
8
8
|
|
|
9
9
|
def test_homepage
|
|
10
10
|
get '/'
|