Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Changelog

## 1.7.0 (UNRELEASED)
## 1.7.0 (2025-01-30)

* Introduce new `:before_attr_assign` policy chain which allows to
access the `model` instance before the parameters are assigned.

* Introduce new `model_includes` DSL method which can be used to eager load
associations in Model operations. See the [corresponding section in the README](README.md#including-associated-records)
for more information.

* Fix bug with lazy authorization in `RailsOps::Operation::Model::Update`
operation which used a version of the `model` which was missing some
attributes.
Expand Down
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,34 @@ end
As this base class is very minimalistic, it is recommended to fully read and
comprehend its source code.

### Including associated records

Normaly, when inheriting from `RailsOps::Operation::Model::Load` (as well as from the
`Update` and the `Destroy` operations respectively), RailsOps only loads the instance
of the model specified by the `id` parameter. In some cases, you'd want to eagerly load
associations of the model, e.g. when you need to access associated records.

For this, RailsOps provides the `model_includes` DSL method, with which you can
pass-in associations to eager load (the value will simply be passed on to an `includes`
call). See the following code snipped for an example:

```ruby
class Operations::User::Load < RailsOps::Operation::Model::Load
schema3 do
int! :id, cast_str: true
end

model ::User

# This will result in RailsOps eagerly loading the `posts`
# association, as well as the comments and authors of the
# comments.
# The call that RailsOps will create is:
# User.includes(posts: { comments: :author }).find_by(id: params[:id])
model_includes posts: { comments: :author }
end
```

### Parameter extraction for create and update

As mentioned before, the `Create` and `Update` base classes provide an
Expand Down
8 changes: 8 additions & 0 deletions lib/rails_ops/operation/model/load.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ class RailsOps::Operation::Model::Load < RailsOps::Operation::Model
class_attribute :_lock_model_at_build
class_attribute :_load_model_authorization_action
class_attribute :_lock_mode
class_attribute :_model_includes

policy :on_init do
model
Expand Down Expand Up @@ -64,6 +65,10 @@ def model_id_field
:id
end

def self.model_includes(includes)
self._model_includes = includes
end

def find_model
unless params[model_id_field]
fail "Param #{model_id_field.inspect} must be given."
Expand All @@ -75,6 +80,9 @@ def find_model
# Express intention to lock if required
relation = lock_relation(relation)

# Apply includes if given in the operation
relation = relation.includes(self.class._model_includes) if self.class._model_includes.present?

# Fetch (and possibly lock) model
model = relation.find_by!(model_id_field => params[model_id_field])

Expand Down