rails_ops 1.1.22 → 1.1.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rubocop.yml +17 -0
- data/.github/workflows/ruby.yml +37 -7
- data/.gitignore +2 -0
- data/.rubocop.yml +1 -0
- data/Appraisals +19 -0
- data/CHANGELOG.md +20 -1
- data/LICENSE +1 -1
- data/README.md +98 -8
- data/Rakefile +4 -0
- data/VERSION +1 -1
- data/gemfiles/rails_5.1.gemfile +7 -0
- data/gemfiles/rails_5.2.gemfile +7 -0
- data/gemfiles/rails_6.0.gemfile +7 -0
- data/gemfiles/rails_6.1.gemfile +7 -0
- data/gemfiles/rails_7.0.gemfile +7 -0
- 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/model_mixins/sti_fixes.rb +17 -0
- data/lib/rails_ops/model_mixins/virtual_attributes/virtual_column_wrapper.rb +4 -0
- data/lib/rails_ops/model_mixins.rb +1 -0
- data/lib/rails_ops.rb +1 -0
- data/rails_ops.gemspec +14 -6
- 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/config/application.rb +13 -2
- 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/create_test.rb +16 -0
- data/test/unit/rails_ops/operation/model/sti_test.rb +70 -0
- data/test/unit/rails_ops/operation/model/update_test.rb +71 -0
- metadata +99 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f526737c309842ce86558e77bc8ac5292d0d5e4faa82a848926cb03e725e51cf
|
4
|
+
data.tar.gz: fba2d918a81609ce6c778eecfe772d0aa252932403774234718309764b2ba348
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3abbc42c29d64386772eceb6095edeecf667ac65987f83acaebe9e93f9a1c6d030536130f9d5430073a6beb8f91e9162f86d0d4e624e214e2a2377ed006ef41
|
7
|
+
data.tar.gz: 5c396aae16103eeec31349daf26708c6eb24b66c9cf39b29a40a1f70e7686d1b6c6b21c8e49af6c5bd000b3ad24ef18c0beb8cf088094192dbaf70a6a45fe512
|
@@ -0,0 +1,17 @@
|
|
1
|
+
name: Rubocop check
|
2
|
+
on: push
|
3
|
+
|
4
|
+
jobs:
|
5
|
+
verify:
|
6
|
+
name: Test
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
|
9
|
+
steps:
|
10
|
+
- uses: actions/checkout@v1
|
11
|
+
- name: Set up Ruby
|
12
|
+
uses: ruby/setup-ruby@v1
|
13
|
+
with:
|
14
|
+
ruby-version: 3.0.1
|
15
|
+
bundler-cache: true
|
16
|
+
- name: Run rubocop
|
17
|
+
run: bundle exec rubocop
|
data/.github/workflows/ruby.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
name:
|
1
|
+
name: Unit tests
|
2
2
|
|
3
3
|
on:
|
4
4
|
push:
|
@@ -12,16 +12,46 @@ jobs:
|
|
12
12
|
strategy:
|
13
13
|
fail-fast: false
|
14
14
|
matrix:
|
15
|
-
|
16
|
-
|
15
|
+
include:
|
16
|
+
- rails-version: '5.1'
|
17
|
+
ruby-version: '2.3.0'
|
18
|
+
- rails-version: '5.1'
|
19
|
+
ruby-version: '2.5.1'
|
20
|
+
- rails-version: '5.2'
|
21
|
+
ruby-version: '2.3.0'
|
22
|
+
- rails-version: '5.2'
|
23
|
+
ruby-version: '2.5.1'
|
24
|
+
- rails-version: '5.2'
|
25
|
+
ruby-version: '2.6.2'
|
26
|
+
- rails-version: '6.0'
|
27
|
+
ruby-version: '2.5.1'
|
28
|
+
- rails-version: '6.0'
|
29
|
+
ruby-version: '2.6.2'
|
30
|
+
- rails-version: '6.0'
|
31
|
+
ruby-version: '2.7.1'
|
32
|
+
- rails-version: '6.1'
|
33
|
+
ruby-version: '2.5.1'
|
34
|
+
- rails-version: '6.1'
|
35
|
+
ruby-version: '2.6.2'
|
36
|
+
- rails-version: '6.1'
|
37
|
+
ruby-version: '2.7.1'
|
38
|
+
- rails-version: '6.1'
|
39
|
+
ruby-version: '3.0.1'
|
40
|
+
- rails-version: '7.0'
|
41
|
+
ruby-version: '2.7.1'
|
42
|
+
- rails-version: '7.0'
|
43
|
+
ruby-version: '3.0.1'
|
44
|
+
- rails-version: '7.0'
|
45
|
+
ruby-version: '3.1.0'
|
46
|
+
name: Test against Ruby ${{ matrix.ruby-version }} / Rails ${{ matrix.rails-version }}
|
47
|
+
env:
|
48
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/rails_${{ matrix.rails-version }}.gemfile
|
17
49
|
steps:
|
18
50
|
- uses: actions/checkout@v2
|
19
|
-
- name: Set up Ruby
|
51
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
20
52
|
uses: ruby/setup-ruby@v1
|
21
53
|
with:
|
22
54
|
ruby-version: ${{ matrix.ruby-version }}
|
23
55
|
bundler-cache: true
|
24
56
|
- name: Run rake tests
|
25
|
-
run: bundle exec rake
|
26
|
-
- name: Run rubocop
|
27
|
-
run: bundle exec rubocop
|
57
|
+
run: bundle exec rake
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/Appraisals
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
appraise "rails-7.0" do
|
2
|
+
gem "rails", "~> 7.0.1"
|
3
|
+
end
|
4
|
+
|
5
|
+
appraise "rails-6.1" do
|
6
|
+
gem "rails", "~> 6.1.4"
|
7
|
+
end
|
8
|
+
|
9
|
+
appraise "rails-6.0" do
|
10
|
+
gem "rails", "~> 6.0.4"
|
11
|
+
end
|
12
|
+
|
13
|
+
appraise "rails-5.2" do
|
14
|
+
gem "rails", "~> 5.2.6"
|
15
|
+
end
|
16
|
+
|
17
|
+
appraise "rails-5.1" do
|
18
|
+
gem "rails", "~> 5.1.7"
|
19
|
+
end
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,25 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## 1.1.
|
3
|
+
## 1.1.26 (2022-01-18)
|
4
|
+
|
5
|
+
* #25: Add test matrix for unit tests
|
6
|
+
|
7
|
+
* Add compatibility for Rails 7 and Ruby 3.1.0
|
8
|
+
|
9
|
+
## 1.1.25 (2022-01-17)
|
10
|
+
|
11
|
+
* #24: Add generator `operation` that generates a controller, operations and empty
|
12
|
+
view files
|
13
|
+
|
14
|
+
## 1.1.24 (2021-11-24)
|
15
|
+
|
16
|
+
* Add support for STI in model operations
|
17
|
+
|
18
|
+
## 1.1.23 (2021-11-01)
|
19
|
+
|
20
|
+
* No changes to previous release
|
21
|
+
|
22
|
+
## 1.1.22 (2021-11-01)
|
4
23
|
|
5
24
|
* Add support for lazy model authorization
|
6
25
|
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
[![
|
1
|
+
[![Unit tests](https://github.com/sitrox/rails_ops/actions/workflows/ruby.yml/badge.svg)](https://github.com/sitrox/rails_ops/actions/workflows/ruby.yml)
|
2
|
+
[![Rubocop check](https://github.com/sitrox/rails_ops/actions/workflows/rubocop.yml/badge.svg)](https://github.com/sitrox/rails_ops/actions/workflows/rubocop.yml)
|
2
3
|
[![Gem Version](https://badge.fury.io/rb/rails_ops.svg)](https://badge.fury.io/rb/rails_ops)
|
3
4
|
|
4
5
|
rails_ops
|
@@ -22,9 +23,21 @@ Requirements & Installation
|
|
22
23
|
|
23
24
|
### Requirements
|
24
25
|
|
25
|
-
- RailsOps only works with Rails applications
|
26
|
-
|
27
|
-
|
26
|
+
- RailsOps only works with Rails applications, with the following Rails versions being tested in the CI:
|
27
|
+
* Rails 5.1.x
|
28
|
+
* Rails 5.2.x
|
29
|
+
* Rails 6.0.x
|
30
|
+
* Rails 6.1.x
|
31
|
+
* Rails 7.0.x
|
32
|
+
- Additionally, the following Ruby versions are covered by our unit tests:
|
33
|
+
* 2.3.0
|
34
|
+
* 2.5.1
|
35
|
+
* 2.6.2
|
36
|
+
* 2.7.1
|
37
|
+
* 3.0.1
|
38
|
+
* 3.1.0
|
39
|
+
- Please see the [unit test workflow](https://github.com/sitrox/rails_ops/actions/workflows/ruby.yml) for the combinations of the Rails & Ruby versions, as only compatible versions are tested with each other.
|
40
|
+
- Prior Rails and Ruby versions may be supported but they are not tested in the CI.
|
28
41
|
- Rails Ops' model operations require ActiveRecord but are database / adapter
|
29
42
|
agnostic
|
30
43
|
|
@@ -1194,8 +1207,8 @@ sensible default. See the respective class' source code for details.
|
|
1194
1207
|
In case of operations inheriting from `RailsOps::Operation::Model::Update`, you
|
1195
1208
|
can specify the `model_authorization_action` to be `lazy`, meaning that it will
|
1196
1209
|
only be checked when *performing* the operation, but not on initialization. This
|
1197
|
-
can be useful for displaying readonly forms to users which
|
1198
|
-
|
1210
|
+
can be useful for displaying readonly forms to users which have read-permissions
|
1211
|
+
only:
|
1199
1212
|
|
1200
1213
|
```ruby
|
1201
1214
|
class Operations::User::Update < RailsOps::Operation::Model::Update
|
@@ -1204,7 +1217,7 @@ class Operations::User::Update < RailsOps::Operation::Model::Update
|
|
1204
1217
|
# This automatically calls `authorize_model! :read`. Because it is set to be
|
1205
1218
|
# `lazy`, the authorization will only run when the operation is actually
|
1206
1219
|
# *performed*, and not already at instantiation.
|
1207
|
-
model_authorization_action :
|
1220
|
+
model_authorization_action :update, lazy: true
|
1208
1221
|
end
|
1209
1222
|
```
|
1210
1223
|
|
@@ -1270,6 +1283,34 @@ This block receives the params hash as it would be passed to the sub operation
|
|
1270
1283
|
and allows to modify it. The block's return value is then passed to the
|
1271
1284
|
sub-operation. Do not change the params inplace but instead return a new hash.
|
1272
1285
|
|
1286
|
+
### Single-table inheritance
|
1287
|
+
|
1288
|
+
Model operations also support STI models (Single Table Inheritance). However,
|
1289
|
+
there is the caviat that if you do extend your model in the operation (e.g.
|
1290
|
+
`model Animal do { ... }`), RailsOps automatically creates an anonymous subclass
|
1291
|
+
of the given class (e.g. `Animal`). Operations will always load / create models
|
1292
|
+
that are instances of this anonymous class.
|
1293
|
+
|
1294
|
+
Consider the following operation:
|
1295
|
+
|
1296
|
+
```ruby
|
1297
|
+
class Animal < ApplicationRecord; end
|
1298
|
+
class Bird < Animal; end
|
1299
|
+
class Mouse < Animal; end
|
1300
|
+
|
1301
|
+
class LoadAnimal < RailsOps::Operation::Model::Load
|
1302
|
+
model Animal do
|
1303
|
+
# Something
|
1304
|
+
end
|
1305
|
+
end
|
1306
|
+
|
1307
|
+
bird = Bird.create
|
1308
|
+
op_bird = LoadAnimal.new(id: bird.id)
|
1309
|
+
|
1310
|
+
bird.class # => Class "Bird", extending "Animal"
|
1311
|
+
op_bird.class # => Anonymous class, extending "Animal", not "Bird"
|
1312
|
+
```
|
1313
|
+
|
1273
1314
|
Record extension and virtual records
|
1274
1315
|
------------------------------------
|
1275
1316
|
|
@@ -1460,6 +1501,55 @@ sub-operations, see section *Calling sub-operations* for more information.
|
|
1460
1501
|
Operation Inheritance
|
1461
1502
|
---------------------
|
1462
1503
|
|
1504
|
+
Generators
|
1505
|
+
----------
|
1506
|
+
|
1507
|
+
RailsOps features a generator to easily create a structure for common CRUD-style
|
1508
|
+
constructs. The generator creates the CRUD operations, some empty view files, a
|
1509
|
+
controller and adds an entry in the routing file.
|
1510
|
+
|
1511
|
+
This is e.g. useful when adding a new model to an application, as the basic structure
|
1512
|
+
is usually rather similar.
|
1513
|
+
|
1514
|
+
### Usage
|
1515
|
+
|
1516
|
+
Run the generator using the `operation` generator, specifying the name of the
|
1517
|
+
operation class:
|
1518
|
+
|
1519
|
+
```ruby
|
1520
|
+
rails g operation User
|
1521
|
+
```
|
1522
|
+
|
1523
|
+
This will generate the following operations:
|
1524
|
+
|
1525
|
+
* `app/operations/user/load.rb`
|
1526
|
+
* `app/operations/user/create.rb`
|
1527
|
+
* `app/operations/user/update.rb`
|
1528
|
+
* `app/operations/user/destroy.rb`
|
1529
|
+
|
1530
|
+
as well as the controller `app/controllers/users_controller.rb` and the following
|
1531
|
+
empty view files:
|
1532
|
+
|
1533
|
+
* `app/views/users/index.html.haml`
|
1534
|
+
* `app/views/users/show.html.haml`
|
1535
|
+
* `app/views/users/new.html.haml`
|
1536
|
+
* `app/views/users/edit.html.haml`
|
1537
|
+
|
1538
|
+
It will also add the entry `resources :users` to the `config/routes.rb` file.
|
1539
|
+
|
1540
|
+
If you want to skip the controller, the views or the routes, you can do so using the
|
1541
|
+
flags:
|
1542
|
+
|
1543
|
+
* `--skip-controller`
|
1544
|
+
* `--skip-routes`
|
1545
|
+
* `--skip-views`
|
1546
|
+
|
1547
|
+
Or if you want to skip them all: `--only-operations`.
|
1548
|
+
|
1549
|
+
Of course, at this point, the operations will need some adaptions, especially the
|
1550
|
+
[parameter schemas](#validating-params), and the controllers need the logic for the
|
1551
|
+
success and failure cases, as this depends on your application.
|
1552
|
+
|
1463
1553
|
Caveats
|
1464
1554
|
-------
|
1465
1555
|
|
@@ -1481,4 +1571,4 @@ Rails architecture.
|
|
1481
1571
|
|
1482
1572
|
## Copyright
|
1483
1573
|
|
1484
|
-
Copyright © 2017 -
|
1574
|
+
Copyright © 2017 - 2022 Sitrox. See `LICENSE` for further details.
|
data/Rakefile
CHANGED
@@ -15,11 +15,15 @@ task :gemspec do
|
|
15
15
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
16
16
|
spec.require_paths = ['lib']
|
17
17
|
|
18
|
+
spec.add_development_dependency 'appraisal'
|
18
19
|
spec.add_development_dependency 'bundler'
|
19
20
|
spec.add_development_dependency 'rake'
|
20
21
|
spec.add_development_dependency 'sqlite3'
|
21
22
|
spec.add_development_dependency 'cancancan'
|
23
|
+
spec.add_development_dependency 'pry'
|
24
|
+
spec.add_development_dependency 'colorize'
|
22
25
|
spec.add_development_dependency 'rubocop', '0.47.1'
|
26
|
+
spec.add_development_dependency 'sprockets-rails'
|
23
27
|
spec.add_dependency 'active_type', '>= 1.3.0'
|
24
28
|
spec.add_dependency 'minitest'
|
25
29
|
spec.add_dependency 'rails'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.
|
1
|
+
1.1.26
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Description:
|
2
|
+
Generates CRUD operations, along with a controller, views and an entry in the route file
|
3
|
+
|
4
|
+
Example:
|
5
|
+
bin/rails generate operation User
|
6
|
+
|
7
|
+
This will create:
|
8
|
+
app/operations/user/load.rb
|
9
|
+
app/operations/user/create.rb
|
10
|
+
app/operations/user/update.rb
|
11
|
+
app/operations/user/destroy.rb
|
12
|
+
|
13
|
+
app/controllers/users_controller.rb
|
14
|
+
|
15
|
+
app/views/users/index.html.haml
|
16
|
+
app/views/users/show.html.haml
|
17
|
+
app/views/users/new.html.haml
|
18
|
+
app/views/users/edit.html.haml
|
19
|
+
|
20
|
+
And add a routing entry:
|
21
|
+
resources :users
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class OperationGenerator < Rails::Generators::NamedBase
|
2
|
+
source_root File.expand_path('templates', __dir__)
|
3
|
+
|
4
|
+
class_option :skip_controller, type: :boolean, desc: "Don't add a controller."
|
5
|
+
class_option :skip_views, type: :boolean, desc: "Don't add the views."
|
6
|
+
class_option :skip_routes, type: :boolean, desc: "Don't add routes to config/routes.rb."
|
7
|
+
class_option :only_operations, type: :boolean, desc: 'Only add the operations. This is equal to specifying --skip-controller --skip-routes --skip-views'
|
8
|
+
|
9
|
+
def add_operations
|
10
|
+
@class_name = name.classify
|
11
|
+
@underscored_name = name.underscore
|
12
|
+
@underscored_pluralized_name = name.underscore.pluralize
|
13
|
+
|
14
|
+
operations_path = "app/operations/#{@underscored_name}"
|
15
|
+
|
16
|
+
template 'load.erb', "#{operations_path}/load.rb"
|
17
|
+
template 'create.erb', "#{operations_path}/create.rb"
|
18
|
+
template 'update.erb', "#{operations_path}/update.rb"
|
19
|
+
template 'destroy.erb', "#{operations_path}/destroy.rb"
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_controller
|
23
|
+
return if options[:skip_controller] || options[:only_operations]
|
24
|
+
|
25
|
+
controller_file_path = "app/controllers/#{@underscored_pluralized_name}_controller.rb"
|
26
|
+
@controller_name = "#{@class_name.pluralize}Controller"
|
27
|
+
|
28
|
+
template 'controller.erb', controller_file_path
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_views
|
32
|
+
return if options[:skip_views] || options[:only_operations]
|
33
|
+
|
34
|
+
views_folder = "app/views/#{@underscored_pluralized_name}"
|
35
|
+
|
36
|
+
%w(index show new edit).each do |view|
|
37
|
+
template 'view.erb', "#{views_folder}/#{view}.html.haml"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_routes
|
42
|
+
return if options[:skip_routes] || options[:only_operations]
|
43
|
+
|
44
|
+
route "resources :#{@underscored_pluralized_name}"
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class <%= @controller_name %> < ApplicationController
|
2
|
+
def index; end
|
3
|
+
|
4
|
+
def show
|
5
|
+
op Operations::<%= @class_name %>::Load
|
6
|
+
end
|
7
|
+
|
8
|
+
def new
|
9
|
+
op Operations::<%= @class_name %>::Create
|
10
|
+
end
|
11
|
+
|
12
|
+
def create
|
13
|
+
if run Operations::<%= @class_name %>::Create
|
14
|
+
# handle successful case
|
15
|
+
else
|
16
|
+
# handle error case
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def edit
|
21
|
+
op Operations::<%= @class_name %>::Update
|
22
|
+
end
|
23
|
+
|
24
|
+
def update
|
25
|
+
if run Operations::<%= @class_name %>::Update
|
26
|
+
# handle successful case
|
27
|
+
else
|
28
|
+
# handle error case
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def destroy
|
33
|
+
if run Operations::<%= @class_name %>::Destroy
|
34
|
+
# handle successful case
|
35
|
+
else
|
36
|
+
# handle error case
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
File without changes
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RailsOps
|
2
|
+
module ModelMixins
|
3
|
+
module StiFixes
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
class_methods do
|
7
|
+
def finder_needs_type_condition?
|
8
|
+
base_class.finder_needs_type_condition?
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
base_class.name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -8,5 +8,6 @@ module RailsOps::ModelMixins
|
|
8
8
|
include VirtualAttributes # Provides virtual attributes functionality.
|
9
9
|
include VirtualHasOne # Provides virtual_has_one.
|
10
10
|
include VirtualModelName # Provides virtual_model_name.
|
11
|
+
include StiFixes # Fixes using RailsOps models with STI.
|
11
12
|
end
|
12
13
|
end
|
data/lib/rails_ops.rb
CHANGED
@@ -88,6 +88,7 @@ require 'rails_ops/model_casting.rb'
|
|
88
88
|
require 'rails_ops/model_mixins.rb'
|
89
89
|
require 'rails_ops/model_mixins/ar_extension.rb'
|
90
90
|
require 'rails_ops/model_mixins/parent_op.rb'
|
91
|
+
require 'rails_ops/model_mixins/sti_fixes.rb'
|
91
92
|
require 'rails_ops/model_mixins/virtual_attributes.rb'
|
92
93
|
require 'rails_ops/model_mixins/virtual_attributes/virtual_column_wrapper.rb'
|
93
94
|
require 'rails_ops/model_mixins/virtual_has_one.rb'
|