rails_ops 1.7.7 → 1.7.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dcc75b6ab31d484ef579cb73510e759c4b5f85074a491954b991648e9c9d678a
4
- data.tar.gz: 6c1b1fec40de9cc92ac28b417acd33cc7ca9a61d936a3ecef9b9131758005cd2
3
+ metadata.gz: d40d2ec6a8a45a3725040a4f9fd0837ca7e42d36625827d1253e1722589e2e21
4
+ data.tar.gz: 53c235fe982863f62f0e6a756f6d7be9f127ad7b7693b1f46f4100b7b914bec8
5
5
  SHA512:
6
- metadata.gz: 369d58ccd929715e12b62cea2b38e42bd629accf5f1b1ed7c00bd9b4e8e58eb947b999c7410959262c647052faac33c3ae84cf502cf1d724954c3e8c51189690
7
- data.tar.gz: 7eddc5780ab3daa372af54140b03d7c80d51d6bb2465b6022e3b1eb4a605af11e97b47f9a681be79fe8c12b8f60e0abc87eee42cda5e86dd51e2885a3efaadc5
6
+ metadata.gz: d226ffc592c1c46ed0c536d6e33e3f54342afc59ef6e162670437b7d2847df8d05d213b62ff128de3cb1084e53470a8bd5c7fa37ac875c9e65610ab54585633d
7
+ data.tar.gz: 611fbd338f724d311d32d300677bf378d031891543bced3f074134793a45e106c337ea8a07958a36d6696f355965d0f23f004f14e2b881605cb68c1de58ac257
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.7.8 (2026-03-12)
4
+
5
+ * Add practical examples throughout README covering non-model operations,
6
+ find-or-create patterns, state validation policies, sub-operation
7
+ composition, complete CRUD sets, model defaults, custom authorization
8
+ actions, virtual datetime fields, operation inheritance, and load
9
+ operations for show pages.
10
+
3
11
  ## 1.7.7 (2026-02-24)
4
12
 
5
13
  * Fix `find_model_relation` to merge the returned relation's conditions
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rails_ops (1.7.7)
4
+ rails_ops (1.7.8)
5
5
  active_type (>= 1.3.0)
6
6
  minitest
7
7
  rails (> 4)
data/README.md CHANGED
@@ -245,6 +245,78 @@ end
245
245
  puts Operations::GenerateHelloWorld.run!(name: 'John Doe').result
246
246
  ```
247
247
 
248
+ #### Practical Example: Non-Model Business Logic Operation
249
+
250
+ Operations don't have to involve models. Use the base `RailsOps::Operation`
251
+ class for business logic, background tasks, or service calls:
252
+
253
+ ```ruby
254
+ module Operations::Cache
255
+ class Rebuild < RailsOps::Operation
256
+ schema3 do
257
+ boo? :include_archived, default: false
258
+ boo? :rebuild_counters, default: true
259
+ end
260
+
261
+ # Internal use only (called from background jobs)
262
+ without_authorization
263
+
264
+ protected
265
+
266
+ def perform
267
+ rebuild_counters if osparams.rebuild_counters
268
+ rebuild_search_index
269
+ end
270
+
271
+ private
272
+
273
+ def rebuild_counters
274
+ Category.find_each do |category|
275
+ Category.reset_counters(category.id, :articles)
276
+ end
277
+ end
278
+
279
+ def rebuild_search_index
280
+ Article.where(indexed: false).find_each(&:update_search_index!)
281
+ end
282
+ end
283
+ end
284
+ ```
285
+
286
+ #### Practical Example: Find-or-Create Pattern
287
+
288
+ A common pattern for idempotent operations that either find an existing record
289
+ or create a new one. Since this doesn't fit neatly into `Model::Create` or
290
+ `Model::Load`, use the base `RailsOps::Operation` and expose the result via
291
+ `attr_reader`:
292
+
293
+ ```ruby
294
+ module Operations::Tag
295
+ class FindOrCreate < RailsOps::Operation
296
+ schema3 do
297
+ str! :name
298
+ str? :color
299
+ end
300
+
301
+ without_authorization
302
+
303
+ attr_reader :model
304
+
305
+ protected
306
+
307
+ def perform
308
+ @model = ::Tag.find_or_create_by!(name: osparams.name) do |tag|
309
+ tag.color = osparams.color || '#000000'
310
+ end
311
+ rescue ActiveRecord::RecordNotUnique
312
+ # Race condition: another process created the record between
313
+ # our SELECT and INSERT. Just find the existing one.
314
+ @model = ::Tag.find_by!(name: osparams.name)
315
+ end
316
+ end
317
+ end
318
+ ```
319
+
248
320
  ## Params Handling
249
321
 
250
322
  ### Passing Params to Operations
@@ -526,6 +598,51 @@ In this case the model is not yet set. That will happen later in the `:on_init`
526
598
  It is also important to note, that this block is
527
599
  not guaranteed to be run first in the chain, if multiple blocks have set `:prepend_action` to true.
528
600
 
601
+ #### Practical Example: State Validation Policies
602
+
603
+ Use policies to validate preconditions based on the model's state. This is
604
+ particularly useful in model operations where you want to reject the operation
605
+ before `perform` runs:
606
+
607
+ ```ruby
608
+ module Operations::Article
609
+ class Publish < RailsOps::Operation::Model::Update
610
+ schema3 do
611
+ int! :id
612
+ end
613
+
614
+ model ::Article
615
+
616
+ # Ensure the article is still a draft before publishing.
617
+ # Runs at instantiation time (i.e. when the model is loaded).
618
+ policy :on_init do
619
+ unless model.draft?
620
+ fail 'Only draft articles can be published.'
621
+ end
622
+ end
623
+
624
+ # Ensure the article has required content.
625
+ # Runs just before perform is called.
626
+ policy do
627
+ if model.body.blank?
628
+ fail RailsOps::Exceptions::ValidationFailed,
629
+ 'Article body cannot be empty.'
630
+ end
631
+ end
632
+
633
+ protected
634
+
635
+ def perform
636
+ model.status = 'published'
637
+ model.published_at = Time.current
638
+ super
639
+ end
640
+ end
641
+ end
642
+ ```
643
+
644
+ Use `:on_init` for checks that should prevent even *displaying* a form, and
645
+ `:before_perform` (the default) for checks that should prevent *submitting* it.
529
646
 
530
647
  ## Calling Sub-Operations
531
648
 
@@ -579,6 +696,49 @@ catches any validation errors and re-throws them as
579
696
  {RailsOps::Exceptions::SubOpValidationFailed} which is not caught by the
580
697
  surrounding op.
581
698
 
699
+ #### Practical Example: Composing Operations
700
+
701
+ Here is a realistic example of an operation that uses sub-operations to compose
702
+ a complex workflow:
703
+
704
+ Building on the `Article::Publish` example from the *Policies* section, here
705
+ is a version that also triggers sub-operations after publishing:
706
+
707
+ ```ruby
708
+ module Operations::Article
709
+ class PublishWithNotification < RailsOps::Operation::Model::Update
710
+ schema3 do
711
+ int! :id
712
+ end
713
+
714
+ model ::Article
715
+
716
+ protected
717
+
718
+ def perform
719
+ model.status = 'published'
720
+ model.published_at = Time.current
721
+ super # Save the article
722
+
723
+ with_rollback_on_exception do
724
+ run_sub! Operations::Cache::Rebuild, rebuild_counters: true
725
+ run_sub! Operations::Notification::Send,
726
+ template: 'article_published',
727
+ record_id: model.id,
728
+ record_type: 'Article'
729
+ end
730
+ end
731
+ end
732
+ end
733
+ ```
734
+
735
+ Note the use of `with_rollback_on_exception`: if any sub-operation fails after
736
+ `super` has already saved the article, the exception is re-raised as
737
+ `RailsOps::Exceptions::RollbackRequired`, which is not caught by `run` and
738
+ therefore causes a surrounding transaction to roll back. Without it, the article
739
+ could remain saved even if the notification fails (since `run` catches standard
740
+ validation errors). See section *Transactions* for more details.
741
+
582
742
  ## Contexts
583
743
 
584
744
  Most operations make use of generic parameters like the current user or an
@@ -1046,7 +1206,6 @@ Rails Ops offers multiple ways of disabling authorization:
1046
1206
  end
1047
1207
  ```
1048
1208
 
1049
-
1050
1209
  ## Model Operations
1051
1210
 
1052
1211
  One of the key features of RailsOps is model operations. RailsOps provides
@@ -1360,6 +1519,124 @@ end
1360
1519
  As this base class is very minimalistic, it is recommended to fully read and
1361
1520
  comprehend its source code.
1362
1521
 
1522
+ ### Practical Example: Complete CRUD Operation Set
1523
+
1524
+ Here is a complete, minimal CRUD set for a single model using `schema3`:
1525
+
1526
+ ```ruby
1527
+ # app/operations/category/load.rb
1528
+ module Operations::Category
1529
+ class Load < RailsOps::Operation::Model::Load
1530
+ schema3 do
1531
+ int! :id
1532
+ end
1533
+
1534
+ model ::Category
1535
+ end
1536
+ end
1537
+
1538
+ # app/operations/category/create.rb
1539
+ module Operations::Category
1540
+ class Create < RailsOps::Operation::Model::Create
1541
+ schema3 do
1542
+ hsh? :category do
1543
+ str? :name
1544
+ str? :description
1545
+ end
1546
+ end
1547
+
1548
+ model ::Category
1549
+ end
1550
+ end
1551
+
1552
+ # app/operations/category/update.rb
1553
+ module Operations::Category
1554
+ class Update < RailsOps::Operation::Model::Update
1555
+ schema3 do
1556
+ int! :id
1557
+ hsh? :category do
1558
+ str? :name
1559
+ str? :description
1560
+ end
1561
+ end
1562
+
1563
+ model ::Category
1564
+ end
1565
+ end
1566
+
1567
+ # app/operations/category/destroy.rb
1568
+ module Operations::Category
1569
+ class Destroy < RailsOps::Operation::Model::Destroy
1570
+ schema3 do
1571
+ int! :id
1572
+ end
1573
+
1574
+ model ::Category
1575
+ end
1576
+ end
1577
+ ```
1578
+
1579
+ For `Create` and `Update`, parameter extraction happens automatically: the
1580
+ params nested under the model's `param_key` (`:category`) are assigned to the
1581
+ model. No `perform` method is needed — the base class handles `save!`.
1582
+
1583
+ ### Practical Example: Setting Defaults on Create
1584
+
1585
+ Override `build_model` to set default values or assign associations that aren't
1586
+ part of the user's input:
1587
+
1588
+ ```ruby
1589
+ module Operations::Article
1590
+ class Create < RailsOps::Operation::Model::Create
1591
+ schema3 do
1592
+ hsh? :article do
1593
+ str? :title
1594
+ str? :body
1595
+ int? :category_id
1596
+ end
1597
+ end
1598
+
1599
+ model ::Article
1600
+
1601
+ protected
1602
+
1603
+ def build_model
1604
+ super # Builds the model and assigns params from :article key
1605
+ model.author = context.user
1606
+ model.status = 'draft'
1607
+ end
1608
+ end
1609
+ end
1610
+ ```
1611
+
1612
+ `super` in `build_model` creates a new model instance and assigns the
1613
+ attributes from params. After `super`, you can set additional attributes.
1614
+
1615
+ ### Practical Example: Overriding `build_model` in Update
1616
+
1617
+ In `Update` operations, `build_model` first loads the record (via `Load`), then
1618
+ assigns the params. Override it to modify the model after loading:
1619
+
1620
+ ```ruby
1621
+ module Operations::Token
1622
+ class MarkUsed < RailsOps::Operation::Model::Update
1623
+ schema3 do
1624
+ int! :id
1625
+ end
1626
+
1627
+ model ::Token
1628
+ without_authorization
1629
+
1630
+ protected
1631
+
1632
+ def build_model
1633
+ super # Loads the record and assigns params
1634
+ model.used_at = Time.current
1635
+ end
1636
+ end
1637
+ end
1638
+ ```
1639
+
1363
1640
  ### Including Associated Records
1364
1641
 
1365
1642
  Normally, when inheriting from `RailsOps::Operation::Model::Load` (as well as from the
@@ -1388,6 +1665,46 @@ class Operations::User::Load < RailsOps::Operation::Model::Load
1388
1665
  end
1389
1666
  ```
1390
1667
 
1668
+ #### Practical Example: Load Operation for Show Pages
1669
+
1670
+ A common pattern for "show" pages: a `Load` operation that provides helper
1671
+ methods for loading related data in the view:
1672
+
1673
+ ```ruby
1674
+ module Operations::Frontend::Articles
1675
+ class Show < RailsOps::Operation::Model::Load
1676
+ model ::Article
1677
+ model_includes [:tags, :category, { comments: :author }]
1678
+
1679
+ def recent_comments(limit: 10)
1680
+ model.comments.order(created_at: :desc).limit(limit)
1681
+ end
1682
+
1683
+ def related_articles
1684
+ @related_articles ||= ::Article
1685
+ .where(category_id: model.category_id)
1686
+ .where.not(id: model.id)
1687
+ .limit(5)
1688
+ end
1689
+
1690
+ protected
1691
+
1692
+ # Load operations don't need perform logic, but the base class
1693
+ # raises NotImplementedError, so we override with a no-op.
1694
+ def perform; end
1695
+ end
1696
+ end
1697
+ ```
1698
+
1699
+ In the controller:
1700
+
1701
+ ```ruby
1702
+ def show
1703
+ op Operations::Frontend::Articles::Show
1704
+ # In the view: op.model, op.recent_comments, op.related_articles
1705
+ end
1706
+ ```
1707
+
1391
1708
  ### Parameter Extraction for Create and Update
1392
1709
 
1393
1710
  As mentioned before, the `Create` and `Update` base classes provide an
@@ -1483,6 +1800,43 @@ class Operations::User::Update < RailsOps::Operation::Model::Update
1483
1800
  end
1484
1801
  ```
1485
1802
 
1803
+ #### Practical Example: Custom Authorization Actions
1804
+
1805
+ For operations beyond standard CRUD (e.g., archiving, classifying, publishing),
1806
+ specify custom authorization actions:
1807
+
1808
+ ```ruby
1809
+ module Operations::Article
1810
+ class Archive < RailsOps::Operation::Model::Update
1811
+ schema3 do
1812
+ int! :id
1813
+ end
1814
+
1815
+ load_model_authorization_action :read
1816
+ model_authorization_action :archive
1817
+
1818
+ model ::Article
1819
+
1820
+ protected
1821
+
1822
+ def perform
1823
+ model.archived = true
1824
+ model.archived_at = Time.current
1825
+ model.archived_by = context.user
1826
+ super
1827
+ end
1828
+ end
1829
+ end
1830
+ ```
1831
+
1832
+ In your ability file, define the custom action:
1833
+
1834
+ ```ruby
1835
+ can :archive, Article do |article|
1836
+ article.author_id == user.id || user.admin?
1837
+ end
1838
+ ```
1839
+
1486
1840
  ### Model Nesting
1487
1841
 
1488
1842
  Using active record, multiple nested models can be saved at once by using
@@ -1738,6 +2092,51 @@ class Operations::Order::Checkout < RailsOps::Operation::Model::Update
1738
2092
  end
1739
2093
  ```
1740
2094
 
2095
+ #### Practical Example: Virtual Datetime Fields for Forms
2096
+
2097
+ A very common use case is adding virtual datetime attributes for form inputs
2098
+ that need to be transformed before saving:
2099
+
2100
+ ```ruby
2101
+ module Operations::Event
2102
+ class Create < RailsOps::Operation::Model::Create
2103
+ schema3 do
2104
+ hsh? :event do
2105
+ str? :title
2106
+ str? :virtual_start_datetime
2107
+ str? :virtual_end_datetime
2108
+ boo? :all_day
2109
+ end
2110
+ end
2111
+
2112
+ model ::Event do
2113
+ attribute :virtual_start_datetime, :datetime
2114
+ attribute :virtual_end_datetime, :datetime
2115
+
2116
+ validates :virtual_start_datetime, presence: true, unless: :all_day?
2117
+ validates :virtual_end_datetime, presence: true, unless: :all_day?
2118
+ validates :virtual_end_datetime,
2119
+ comparison: { greater_than_or_equal_to: :virtual_start_datetime },
2120
+ if: -> { !all_day? && virtual_start_datetime.present? }
2121
+ end
2122
+
2123
+ protected
2124
+
2125
+ def build_model
2126
+ super
2127
+
2128
+ if model.all_day?
2129
+ model.start_date = model.virtual_start_datetime&.beginning_of_day
2130
+ model.end_date = model.virtual_end_datetime&.end_of_day
2131
+ else
2132
+ model.start_date = model.virtual_start_datetime
2133
+ model.end_date = model.virtual_end_datetime
2134
+ end
2135
+ end
2136
+ end
2137
+ end
2138
+ ```
2139
+
1741
2140
  ### Combining Real and Virtual Models
1742
2141
 
1743
2142
  You can create operations that work with both persisted and virtual data:
@@ -2127,6 +2526,103 @@ sub-operations, see section *Calling sub-operations* for more information.
2127
2526
 
2128
2527
  ## Operation Inheritance
2129
2528
 
2529
+ Operations support standard Ruby class inheritance. This is useful when multiple
2530
+ models share the same operation pattern. Create an abstract base operation and
2531
+ then inherit from it for each model:
2532
+
2533
+ ```ruby
2534
+ # app/operations/base/toggle_active.rb
2535
+ module Operations::Base
2536
+ class ToggleActive < RailsOps::Operation::Model::Update
2537
+ schema3 do
2538
+ int! :id
2539
+ end
2540
+
2541
+ protected
2542
+
2543
+ def perform
2544
+ model.active = !model.active
2545
+ super
2546
+ end
2547
+ end
2548
+ end
2549
+
2550
+ # app/operations/category/toggle_active.rb
2551
+ module Operations::Category
2552
+ class ToggleActive < Operations::Base::ToggleActive
2553
+ model ::Category
2554
+ end
2555
+ end
2556
+
2557
+ # app/operations/tag/toggle_active.rb
2558
+ module Operations::Tag
2559
+ class ToggleActive < Operations::Base::ToggleActive
2560
+ model ::Tag
2561
+ end
2562
+ end
2563
+ ```
2564
+
2565
+ The base class defines the common schema and behavior. Subclasses only need to
2566
+ specify the `model`. This avoids duplicating logic across many operations.
2567
+
2568
+ Schemas, policies, and authorization settings are all inherited. Subclasses can
2569
+ add additional policies or override methods as needed.
2570
+
2571
+ ### Practical Example: Bulk Insert Operation Base
2572
+
2573
+ Another common base class is for bulk insert operations:
2574
+
2575
+ ```ruby
2576
+ module Operations::Base
2577
+ class BulkCreate < RailsOps::Operation
2578
+ BATCH_SIZE = 500
2579
+
2580
+ without_authorization
2581
+
2582
+ protected
2583
+
2584
+ def perform
2585
+ unique_ids = ids_to_insert.uniq
2586
+ return if unique_ids.empty?
2587
+
2588
+ now = Time.current
2589
+
2590
+ unique_ids.each_slice(self.class::BATCH_SIZE) do |batch|
2591
+ records = build_records(batch, now)
2592
+ target_class.insert_all!(records)
2593
+ rescue ActiveRecord::RecordNotUnique
2594
+ # Race condition: filter out already-existing records and retry
2595
+ existing = existing_ids_for(batch)
2596
+ new_records = records.reject { |r| existing.include?(r[id_column]) }
2597
+ target_class.insert_all!(new_records) if new_records.any?
2598
+ end
2599
+ end
2600
+
2601
+ private
2602
+
2603
+ def ids_to_insert
2604
+ fail NotImplementedError
2605
+ end
2606
+
2607
+ def build_records(_batch, _now)
2608
+ fail NotImplementedError
2609
+ end
2610
+
2611
+ def target_class
2612
+ fail NotImplementedError
2613
+ end
2614
+
2615
+ def id_column
2616
+ :id
2617
+ end
2618
+
2619
+ def existing_ids_for(_batch)
2620
+ fail NotImplementedError
2621
+ end
2622
+ end
2623
+ end
2624
+ ```
2625
+
2130
2626
  ## Generators
2131
2627
 
2132
2628
  RailsOps features a generator to easily create a structure for common CRUD-style
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.7.7
1
+ 1.7.8
data/rails_ops.gemspec CHANGED
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: rails_ops 1.7.7 ruby lib
2
+ # stub: rails_ops 1.7.8 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "rails_ops".freeze
6
- s.version = "1.7.7"
6
+ s.version = "1.7.8"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Sitrox".freeze]
11
- s.date = "2026-02-24"
11
+ s.date = "2026-03-12"
12
12
  s.files = [".github/workflows/rubocop.yml".freeze, ".github/workflows/ruby.yml".freeze, ".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, "Appraisals".freeze, "CHANGELOG.md".freeze, "CLAUDE.md".freeze, "Gemfile".freeze, "Gemfile.lock".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "gemfiles/rails_6.0.gemfile".freeze, "gemfiles/rails_6.1.gemfile".freeze, "gemfiles/rails_7.0.gemfile".freeze, "gemfiles/rails_7.1.gemfile".freeze, "gemfiles/rails_7.2.gemfile".freeze, "gemfiles/rails_8.0.gemfile".freeze, "lib/generators/operation/USAGE".freeze, "lib/generators/operation/operation_generator.rb".freeze, "lib/generators/operation/templates/controller.erb".freeze, "lib/generators/operation/templates/controller_wrapper.erb".freeze, "lib/generators/operation/templates/create.erb".freeze, "lib/generators/operation/templates/destroy.erb".freeze, "lib/generators/operation/templates/load.erb".freeze, "lib/generators/operation/templates/update.erb".freeze, "lib/generators/operation/templates/view.erb".freeze, "lib/rails_ops.rb".freeze, "lib/rails_ops/authorization_backend/abstract.rb".freeze, "lib/rails_ops/authorization_backend/can_can_can.rb".freeze, "lib/rails_ops/configuration.rb".freeze, "lib/rails_ops/context.rb".freeze, "lib/rails_ops/controller_mixin.rb".freeze, "lib/rails_ops/exceptions.rb".freeze, "lib/rails_ops/hooked_job.rb".freeze, "lib/rails_ops/hookup.rb".freeze, "lib/rails_ops/hookup/dsl.rb".freeze, "lib/rails_ops/hookup/dsl_validator.rb".freeze, "lib/rails_ops/hookup/hook.rb".freeze, "lib/rails_ops/log_subscriber.rb".freeze, "lib/rails_ops/mixins.rb".freeze, "lib/rails_ops/mixins/authorization.rb".freeze, "lib/rails_ops/mixins/log_settings.rb".freeze, "lib/rails_ops/mixins/model.rb".freeze, "lib/rails_ops/mixins/model/authorization.rb".freeze, "lib/rails_ops/mixins/model/nesting.rb".freeze, "lib/rails_ops/mixins/param_authorization.rb".freeze, "lib/rails_ops/mixins/policies.rb".freeze, "lib/rails_ops/mixins/require_context.rb".freeze, "lib/rails_ops/mixins/routes.rb".freeze, "lib/rails_ops/mixins/schema_validation.rb".freeze, "lib/rails_ops/mixins/sub_ops.rb".freeze, "lib/rails_ops/model_mixins.rb".freeze, "lib/rails_ops/model_mixins/ar_extension.rb".freeze, "lib/rails_ops/model_mixins/marshalling.rb".freeze, "lib/rails_ops/model_mixins/parent_op.rb".freeze, "lib/rails_ops/model_mixins/sti_fixes.rb".freeze, "lib/rails_ops/model_mixins/virtual_attributes.rb".freeze, "lib/rails_ops/model_mixins/virtual_attributes/virtual_column_wrapper.rb".freeze, "lib/rails_ops/model_mixins/virtual_has_one.rb".freeze, "lib/rails_ops/model_mixins/virtual_model_name.rb".freeze, "lib/rails_ops/operation.rb".freeze, "lib/rails_ops/operation/model.rb".freeze, "lib/rails_ops/operation/model/create.rb".freeze, "lib/rails_ops/operation/model/destroy.rb".freeze, "lib/rails_ops/operation/model/load.rb".freeze, "lib/rails_ops/operation/model/update.rb".freeze, "lib/rails_ops/profiler.rb".freeze, "lib/rails_ops/profiler/node.rb".freeze, "lib/rails_ops/railtie.rb".freeze, "lib/rails_ops/scoped_env.rb".freeze, "lib/rails_ops/virtual_model.rb".freeze, "rails_ops.gemspec".freeze, "test/db/models.rb".freeze, "test/db/schema.rb".freeze, "test/dummy/Rakefile".freeze, "test/dummy/app/assets/config/manifest.js".freeze, "test/dummy/app/assets/images/.keep".freeze, "test/dummy/app/assets/javascripts/application.js".freeze, "test/dummy/app/assets/javascripts/cable.js".freeze, "test/dummy/app/assets/javascripts/channels/.keep".freeze, "test/dummy/app/assets/stylesheets/application.css".freeze, "test/dummy/app/channels/application_cable/channel.rb".freeze, "test/dummy/app/channels/application_cable/connection.rb".freeze, "test/dummy/app/controllers/application_controller.rb".freeze, "test/dummy/app/controllers/concerns/.keep".freeze, "test/dummy/app/controllers/group_controller.rb".freeze, "test/dummy/app/helpers/application_helper.rb".freeze, "test/dummy/app/jobs/application_job.rb".freeze, "test/dummy/app/mailers/application_mailer.rb".freeze, "test/dummy/app/models/ability.rb".freeze, "test/dummy/app/models/animal.rb".freeze, "test/dummy/app/models/application_record.rb".freeze, "test/dummy/app/models/bird.rb".freeze, "test/dummy/app/models/cat.rb".freeze, "test/dummy/app/models/computer.rb".freeze, "test/dummy/app/models/concerns/.keep".freeze, "test/dummy/app/models/cpu.rb".freeze, "test/dummy/app/models/dog.rb".freeze, "test/dummy/app/models/flower.rb".freeze, "test/dummy/app/models/group.rb".freeze, "test/dummy/app/models/mainboard.rb".freeze, "test/dummy/app/models/nightingale.rb".freeze, "test/dummy/app/models/phoenix.rb".freeze, "test/dummy/app/models/user.rb".freeze, "test/dummy/app/views/layouts/application.html.erb".freeze, "test/dummy/app/views/layouts/mailer.html.erb".freeze, "test/dummy/app/views/layouts/mailer.text.erb".freeze, "test/dummy/bin/bundle".freeze, "test/dummy/bin/rails".freeze, "test/dummy/bin/rake".freeze, "test/dummy/bin/setup".freeze, "test/dummy/bin/update".freeze, "test/dummy/bin/yarn".freeze, "test/dummy/config.ru".freeze, "test/dummy/config/application.rb".freeze, "test/dummy/config/boot.rb".freeze, "test/dummy/config/cable.yml".freeze, "test/dummy/config/database.yml".freeze, "test/dummy/config/environment.rb".freeze, "test/dummy/config/environments/development.rb".freeze, "test/dummy/config/environments/production.rb".freeze, "test/dummy/config/environments/test.rb".freeze, "test/dummy/config/hookup.rb".freeze, "test/dummy/config/initializers/application_controller_renderer.rb".freeze, "test/dummy/config/initializers/assets.rb".freeze, "test/dummy/config/initializers/backtrace_silencers.rb".freeze, "test/dummy/config/initializers/cookies_serializer.rb".freeze, "test/dummy/config/initializers/filter_parameter_logging.rb".freeze, "test/dummy/config/initializers/inflections.rb".freeze, "test/dummy/config/initializers/mime_types.rb".freeze, "test/dummy/config/initializers/rails_ops.rb".freeze, "test/dummy/config/initializers/wrap_parameters.rb".freeze, "test/dummy/config/locales/en.yml".freeze, "test/dummy/config/puma.rb".freeze, "test/dummy/config/routes.rb".freeze, "test/dummy/config/secrets.yml".freeze, "test/dummy/config/spring.rb".freeze, "test/dummy/db/schema.rb".freeze, "test/dummy/lib/assets/.keep".freeze, "test/dummy/log/.keep".freeze, "test/dummy/package.json".freeze, "test/dummy/public/404.html".freeze, "test/dummy/public/422.html".freeze, "test/dummy/public/500.html".freeze, "test/dummy/public/apple-touch-icon-precomposed.png".freeze, "test/dummy/public/apple-touch-icon.png".freeze, "test/dummy/public/favicon.ico".freeze, "test/dummy/tmp/.keep".freeze, "test/test_helper.rb".freeze, "test/unit/rails_ops/generators/operation_generator_test.rb".freeze, "test/unit/rails_ops/hookup_test.rb".freeze, "test/unit/rails_ops/mixins/controller_test.rb".freeze, "test/unit/rails_ops/mixins/model/deep_nesting_test.rb".freeze, "test/unit/rails_ops/mixins/model/marshalling_test.rb".freeze, "test/unit/rails_ops/mixins/param_authorization_test.rb".freeze, "test/unit/rails_ops/mixins/policies_test.rb".freeze, "test/unit/rails_ops/operation/auth_test.rb".freeze, "test/unit/rails_ops/operation/model/create_test.rb".freeze, "test/unit/rails_ops/operation/model/destroy_test.rb".freeze, "test/unit/rails_ops/operation/model/load_test.rb".freeze, "test/unit/rails_ops/operation/model/sti_test.rb".freeze, "test/unit/rails_ops/operation/model/update_test.rb".freeze, "test/unit/rails_ops/operation/model_test.rb".freeze, "test/unit/rails_ops/operation/update_lazy_auth_test.rb".freeze, "test/unit/rails_ops/operation_test.rb".freeze, "test/unit/rails_ops/profiler_test.rb".freeze]
13
13
  s.homepage = "https://github.com/sitrox/rails_ops".freeze
14
14
  s.licenses = ["MIT".freeze]
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_ops
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.7
4
+ version: 1.7.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sitrox
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-02-24 00:00:00.000000000 Z
10
+ date: 2026-03-12 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: active_type