rails_ops 1.1.21 → 1.1.25
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/ruby.yml +27 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +17 -0
- data/LICENSE +1 -1
- data/README.md +105 -15
- data/Rakefile +4 -0
- data/VERSION +1 -1
- data/lib/generators/operation/USAGE +21 -0
- data/lib/generators/operation/operation_generator.rb +46 -0
- data/lib/generators/operation/templates/controller.erb +39 -0
- data/lib/generators/operation/templates/create.erb +11 -0
- data/lib/generators/operation/templates/destroy.erb +9 -0
- data/lib/generators/operation/templates/load.erb +5 -0
- data/lib/generators/operation/templates/update.erb +12 -0
- data/lib/generators/operation/templates/view.erb +0 -0
- data/lib/rails_ops/mixins/model/authorization.rb +3 -1
- data/lib/rails_ops/model_mixins/sti_fixes.rb +21 -0
- data/lib/rails_ops/model_mixins.rb +1 -0
- data/lib/rails_ops/operation/model/update.rb +17 -2
- data/lib/rails_ops.rb +1 -0
- data/rails_ops.gemspec +25 -27
- data/test/dummy/app/models/animal.rb +1 -0
- data/test/dummy/app/models/bird.rb +1 -0
- data/test/dummy/app/models/cat.rb +1 -0
- data/test/dummy/app/models/dog.rb +1 -0
- data/test/dummy/app/models/flower.rb +7 -0
- data/test/dummy/app/models/nightingale.rb +1 -0
- data/test/dummy/app/models/phoenix.rb +1 -0
- data/test/dummy/app/models/user.rb +3 -0
- data/test/dummy/config/application.rb +12 -1
- data/test/dummy/config/environments/test.rb +1 -1
- data/test/dummy/config/initializers/backtrace_silencers.rb +1 -1
- data/test/dummy/db/schema.rb +8 -0
- data/test/test_helper.rb +2 -0
- data/test/unit/rails_ops/generators/operation_generator_test.rb +170 -0
- data/test/unit/rails_ops/operation/model/sti_test.rb +70 -0
- data/test/unit/rails_ops/operation/model/update_test.rb +26 -0
- data/test/unit/rails_ops/operation/update_auth_test.rb +62 -0
- data/test/unit/rails_ops/operation/update_lazy_auth_test.rb +63 -0
- metadata +99 -10
- data/.travis.yml +0 -11
@@ -0,0 +1 @@
|
|
1
|
+
class Bird < Animal; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Cat < Animal; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Dog < Animal; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Nightingale < Bird; end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Phoenix < Bird; end
|
@@ -1,6 +1,17 @@
|
|
1
1
|
require_relative 'boot'
|
2
2
|
|
3
|
-
require 'rails
|
3
|
+
require 'rails'
|
4
|
+
|
5
|
+
require 'active_model/railtie'
|
6
|
+
require 'active_job/railtie'
|
7
|
+
require 'active_record/railtie'
|
8
|
+
# require "active_storage/engine"
|
9
|
+
require 'action_controller/railtie'
|
10
|
+
require 'action_mailer/railtie'
|
11
|
+
require 'action_view/railtie'
|
12
|
+
require 'action_cable/engine'
|
13
|
+
require 'sprockets/railtie'
|
14
|
+
require 'rails/test_unit/railtie'
|
4
15
|
|
5
16
|
Bundler.require(*Rails.groups)
|
6
17
|
require 'rails_ops'
|
@@ -10,7 +10,7 @@ Rails.application.configure do
|
|
10
10
|
# Do not eager load code on boot. This avoids loading your whole application
|
11
11
|
# just for the purpose of running a single test. If you are using a tool that
|
12
12
|
# preloads Rails for running tests, you may have to set it to true.
|
13
|
-
config.eager_load =
|
13
|
+
config.eager_load = true
|
14
14
|
|
15
15
|
# Configure public file server for tests with Cache-Control for performance.
|
16
16
|
config.public_file_server.enabled = true
|
@@ -4,4 +4,4 @@
|
|
4
4
|
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
|
5
5
|
|
6
6
|
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
|
7
|
-
|
7
|
+
Rails.backtrace_cleaner.remove_silencers!
|
data/test/dummy/db/schema.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require File.expand_path('../../test/dummy/config/environment.rb', __FILE__)
|
2
2
|
# ActiveRecord::Migrator.migrations_paths = [File.expand_path("../../test/dummy/db/migrate", __FILE__)]
|
3
3
|
require 'rails/test_help'
|
4
|
+
require 'pry'
|
5
|
+
require 'colorize'
|
4
6
|
|
5
7
|
# Filter out Minitest backtrace while allowing backtrace from other libraries
|
6
8
|
# to be shown.
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'generators/operation/operation_generator'
|
3
|
+
|
4
|
+
class OperationGeneratorTest < Rails::Generators::TestCase
|
5
|
+
tests OperationGenerator
|
6
|
+
destination File.expand_path('../../../tmp', File.dirname(__FILE__))
|
7
|
+
|
8
|
+
setup do
|
9
|
+
prepare_destination
|
10
|
+
|
11
|
+
# Add an empty routes file
|
12
|
+
Dir.mkdir(File.join(destination_root, 'config'))
|
13
|
+
File.open(File.join(destination_root, 'config', 'routes.rb'), 'w') do |f|
|
14
|
+
f.write <<~ROUTES
|
15
|
+
Rails.application.routes.draw do
|
16
|
+
end
|
17
|
+
ROUTES
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_all
|
22
|
+
run_generator ['User']
|
23
|
+
|
24
|
+
# Check that operations are generated
|
25
|
+
assert_operations
|
26
|
+
|
27
|
+
# Check that views are generated
|
28
|
+
assert_views
|
29
|
+
|
30
|
+
# Check that the controller is generated
|
31
|
+
assert_controller
|
32
|
+
|
33
|
+
# Check that the routes entry is added
|
34
|
+
assert_routes
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_no_views
|
38
|
+
run_generator ['User', '--skip-views']
|
39
|
+
|
40
|
+
assert_operations
|
41
|
+
assert_controller
|
42
|
+
assert_routes
|
43
|
+
|
44
|
+
# Check that the views were skipped
|
45
|
+
%w(index show new edit).each do |view|
|
46
|
+
assert_no_file "app/views/users/#{view}.html.haml"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_no_controller
|
51
|
+
run_generator ['User', '--skip-controller']
|
52
|
+
|
53
|
+
assert_operations
|
54
|
+
assert_views
|
55
|
+
assert_routes
|
56
|
+
|
57
|
+
# Check that the controller was skipped
|
58
|
+
assert_no_file 'app/controllers/users_controller.rb'
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_no_routes
|
62
|
+
run_generator ['User', '--skip-routes']
|
63
|
+
|
64
|
+
assert_operations
|
65
|
+
assert_views
|
66
|
+
assert_controller
|
67
|
+
|
68
|
+
# Check that the routes were not added
|
69
|
+
assert_file 'config/routes.rb' do |routes|
|
70
|
+
assert_no_match(/resources :users/, routes)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_skip_all
|
75
|
+
run_generator ['User', '--skip-controller', '--skip-routes', '--skip-views']
|
76
|
+
|
77
|
+
assert_operations
|
78
|
+
|
79
|
+
# Check that the controller was skipped
|
80
|
+
assert_no_file 'app/controllers/users_controller.rb'
|
81
|
+
|
82
|
+
# Check that the routes were not added
|
83
|
+
assert_file 'config/routes.rb' do |routes|
|
84
|
+
assert_no_match(/resources :users/, routes)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Check that the views were skipped
|
88
|
+
%w(index show new edit).each do |view|
|
89
|
+
assert_no_file "app/views/users/#{view}.html.haml"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_only_operations
|
94
|
+
run_generator ['User', '--only-operations']
|
95
|
+
|
96
|
+
assert_operations
|
97
|
+
|
98
|
+
# Check that the controller was skipped
|
99
|
+
assert_no_file 'app/controllers/users_controller.rb'
|
100
|
+
|
101
|
+
# Check that the routes were not added
|
102
|
+
assert_file 'config/routes.rb' do |routes|
|
103
|
+
assert_no_match(/resources :users/, routes)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Check that the views were skipped
|
107
|
+
%w(index show new edit).each do |view|
|
108
|
+
assert_no_file "app/views/users/#{view}.html.haml"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_lowercase_name
|
113
|
+
run_generator ['user']
|
114
|
+
|
115
|
+
# Check that operations are generated
|
116
|
+
assert_operations
|
117
|
+
|
118
|
+
# Check that views are generated
|
119
|
+
assert_views
|
120
|
+
|
121
|
+
# Check that the controller is generated
|
122
|
+
assert_controller
|
123
|
+
|
124
|
+
# Check that the routes entry is added
|
125
|
+
assert_routes
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def assert_operations
|
131
|
+
assert_file 'app/operations/user/create.rb' do |operation|
|
132
|
+
assert_match(/module Operations::User/, operation)
|
133
|
+
assert_match(/class Create < RailsOps::Operation::Model::Create/, operation)
|
134
|
+
assert_match(/model ::User/, operation)
|
135
|
+
end
|
136
|
+
assert_file 'app/operations/user/destroy.rb' do |operation|
|
137
|
+
assert_match(/module Operations::User/, operation)
|
138
|
+
assert_match(/class Destroy < RailsOps::Operation::Model::Destroy/, operation)
|
139
|
+
assert_match(/model ::User/, operation)
|
140
|
+
end
|
141
|
+
assert_file 'app/operations/user/load.rb' do |operation|
|
142
|
+
assert_match(/module Operations::User/, operation)
|
143
|
+
assert_match(/class Load < RailsOps::Operation::Model::Load/, operation)
|
144
|
+
assert_match(/model ::User/, operation)
|
145
|
+
end
|
146
|
+
assert_file 'app/operations/user/update.rb' do |operation|
|
147
|
+
assert_match(/module Operations::User/, operation)
|
148
|
+
assert_match(/class Update < RailsOps::Operation::Model::Update/, operation)
|
149
|
+
assert_match(/model ::User/, operation)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def assert_views
|
154
|
+
%w(index show new edit).each do |view|
|
155
|
+
assert_file "app/views/users/#{view}.html.haml"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def assert_controller
|
160
|
+
assert_file 'app/controllers/users_controller.rb' do |controller|
|
161
|
+
assert_match(/class UsersController < ApplicationController/, controller)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def assert_routes
|
166
|
+
assert_file 'config/routes.rb' do |routes|
|
167
|
+
assert_match(/resources :users/, routes)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class RailsOps::Operation::Model::StiTest < ActiveSupport::TestCase
|
4
|
+
include TestHelper
|
5
|
+
|
6
|
+
setup do
|
7
|
+
@dog = Dog.create!
|
8
|
+
@cat = Cat.create!
|
9
|
+
@phoenix = Phoenix.create!
|
10
|
+
@nightingale = Nightingale.create!
|
11
|
+
end
|
12
|
+
|
13
|
+
LOAD_ANIMAL_OP = Class.new(RailsOps::Operation::Model::Load) do
|
14
|
+
model Animal do
|
15
|
+
attribute :my_virtual_animal_name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
LOAD_DOG_OP = Class.new(RailsOps::Operation::Model::Load) do
|
20
|
+
model Dog do
|
21
|
+
attribute :my_virtual_dog_name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
LOAD_BIRD_OP = Class.new(RailsOps::Operation::Model::Load) do
|
26
|
+
model Bird do
|
27
|
+
attribute :my_virtual_bird_name
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
LOAD_PHOENIX_OP = Class.new(RailsOps::Operation::Model::Load) do
|
32
|
+
model Phoenix do
|
33
|
+
attribute :my_virtual_phoenix_name
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_load_animal
|
38
|
+
model = LOAD_ANIMAL_OP.new(id: @dog.id).model
|
39
|
+
assert_equal 'Dog', model.type
|
40
|
+
assert model.is_a?(LOAD_ANIMAL_OP.model)
|
41
|
+
assert_nothing_raised { model.my_virtual_animal_name = 'Lenny' }
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_load_dog
|
45
|
+
model = LOAD_DOG_OP.new(id: @dog.id).model
|
46
|
+
|
47
|
+
assert_equal 'Dog', model.type
|
48
|
+
assert model.is_a?(LOAD_DOG_OP.model)
|
49
|
+
assert_nothing_raised { model.my_virtual_dog_name = 'Lenny' }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_load_birds
|
53
|
+
phoenix = LOAD_BIRD_OP.new(id: @phoenix.id).model
|
54
|
+
nightingale = LOAD_BIRD_OP.new(id: @nightingale.id).model
|
55
|
+
|
56
|
+
assert_equal 'Phoenix', phoenix.type
|
57
|
+
assert phoenix.is_a?(LOAD_BIRD_OP.model)
|
58
|
+
assert nightingale.is_a?(LOAD_BIRD_OP.model)
|
59
|
+
assert_nothing_raised { phoenix.my_virtual_bird_name = 'Lenny' }
|
60
|
+
assert_nothing_raised { nightingale.my_virtual_bird_name = 'Lenny' }
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_load_phoenix
|
64
|
+
model = LOAD_PHOENIX_OP.new(id: @phoenix.id).model
|
65
|
+
|
66
|
+
assert_equal 'Phoenix', model.type
|
67
|
+
assert model.is_a?(LOAD_PHOENIX_OP.model)
|
68
|
+
assert_nothing_raised { model.my_virtual_phoenix_name = 'Lenny' }
|
69
|
+
end
|
70
|
+
end
|
@@ -7,6 +7,12 @@ class RailsOps::Operation::Model::UpdateTest < ActiveSupport::TestCase
|
|
7
7
|
model Group
|
8
8
|
end
|
9
9
|
|
10
|
+
FLOWER_OP = Class.new(RailsOps::Operation::Model::Update) do
|
11
|
+
model Flower do
|
12
|
+
attribute :color
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
10
16
|
def test_basic
|
11
17
|
g = Group.create
|
12
18
|
op = BASIC_OP.new(id: g.id)
|
@@ -19,4 +25,24 @@ class RailsOps::Operation::Model::UpdateTest < ActiveSupport::TestCase
|
|
19
25
|
op = BASIC_OP.new(id: g.id)
|
20
26
|
assert_equal op, op.model.parent_op
|
21
27
|
end
|
28
|
+
|
29
|
+
def test_issue_59992
|
30
|
+
flower1 = Flower.create!(planted: true)
|
31
|
+
flower2 = Flower.create!(planted: false)
|
32
|
+
|
33
|
+
op = FLOWER_OP.new(id: flower1.id)
|
34
|
+
|
35
|
+
assert op.model.respond_to?(:color)
|
36
|
+
assert op.model.is_a?(FLOWER_OP.model)
|
37
|
+
|
38
|
+
op.model.color = :red
|
39
|
+
|
40
|
+
assert_equal :red, op.model.color
|
41
|
+
|
42
|
+
op = FLOWER_OP.new(id: flower2.id)
|
43
|
+
|
44
|
+
assert_raises ActiveRecord::RecordNotFound do
|
45
|
+
op.model
|
46
|
+
end
|
47
|
+
end
|
22
48
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'rails_ops/authorization_backend/can_can_can'
|
3
|
+
require 'cancancan'
|
4
|
+
|
5
|
+
class RailsOps::Operation::UpdateLazyAuthTest < ActiveSupport::TestCase
|
6
|
+
include TestHelper
|
7
|
+
|
8
|
+
BASIC_OP = Class.new(RailsOps::Operation::Model::Update) do
|
9
|
+
model ::Group
|
10
|
+
|
11
|
+
model_authorization_action :update
|
12
|
+
|
13
|
+
def perform
|
14
|
+
fail osparams.exception if osparams.exception
|
15
|
+
@done = true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
ABILITY = Class.new do
|
20
|
+
include CanCan::Ability
|
21
|
+
|
22
|
+
def initialize(read: false, update: false)
|
23
|
+
can :read, Group if read
|
24
|
+
can :update, Group if update
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
setup do
|
29
|
+
Group.create!(id: 1, name: 'Group')
|
30
|
+
RailsOps.config.authorization_backend = 'RailsOps::AuthorizationBackend::CanCanCan'
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_unpermitted_read
|
34
|
+
ctx = RailsOps::Context.new(ability: ABILITY.new(read: true))
|
35
|
+
assert_raises CanCan::AccessDenied do
|
36
|
+
BASIC_OP.new(ctx, id: 1)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_permitted_read
|
41
|
+
ctx = RailsOps::Context.new(ability: ABILITY.new(read: true))
|
42
|
+
assert_nothing_raised do
|
43
|
+
BASIC_OP.new(ctx, id: 1)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_unpermitted_update
|
48
|
+
ctx = RailsOps::Context.new(ability: ABILITY.new(read: true))
|
49
|
+
op = BASIC_OP.new(ctx, id: 1)
|
50
|
+
assert_raises CanCan::AccessDenied do
|
51
|
+
op.run!
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_permitted_update
|
56
|
+
ctx = RailsOps::Context.new(ability: ABILITY.new(read: true, update: true))
|
57
|
+
op = BASIC_OP.new(ctx, id: 1)
|
58
|
+
assert_nothing_raised do
|
59
|
+
op.run!
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'rails_ops/authorization_backend/can_can_can'
|
3
|
+
require 'cancancan'
|
4
|
+
|
5
|
+
class RailsOps::Operation::UpdateLazyAuthTest < ActiveSupport::TestCase
|
6
|
+
include TestHelper
|
7
|
+
|
8
|
+
BASIC_OP = Class.new(RailsOps::Operation::Model::Update) do
|
9
|
+
model ::Group
|
10
|
+
|
11
|
+
model_authorization_action :update, lazy: true
|
12
|
+
|
13
|
+
def perform
|
14
|
+
fail osparams.exception if osparams.exception
|
15
|
+
@done = true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
ABILITY = Class.new do
|
20
|
+
include CanCan::Ability
|
21
|
+
|
22
|
+
def initialize(read: false, update: false)
|
23
|
+
can :read, Group if read
|
24
|
+
can :update, Group if update
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
setup do
|
29
|
+
Group.delete_all
|
30
|
+
Group.create!(id: 1, name: 'Group')
|
31
|
+
RailsOps.config.authorization_backend = 'RailsOps::AuthorizationBackend::CanCanCan'
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_unpermitted_read
|
35
|
+
ctx = RailsOps::Context.new(ability: ABILITY.new)
|
36
|
+
assert_raises CanCan::AccessDenied do
|
37
|
+
BASIC_OP.new(ctx, id: 1)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_permitted_read
|
42
|
+
ctx = RailsOps::Context.new(ability: ABILITY.new(read: true))
|
43
|
+
assert_nothing_raised do
|
44
|
+
BASIC_OP.new(ctx, id: 1)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_unpermitted_update
|
49
|
+
ctx = RailsOps::Context.new(ability: ABILITY.new(read: true))
|
50
|
+
op = BASIC_OP.new(ctx, id: 1)
|
51
|
+
assert_raises CanCan::AccessDenied do
|
52
|
+
op.run!
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_permitted_update
|
57
|
+
ctx = RailsOps::Context.new(ability: ABILITY.new(read: true, update: true))
|
58
|
+
op = BASIC_OP.new(ctx, id: 1)
|
59
|
+
assert_nothing_raised do
|
60
|
+
op.run!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|