-
Notifications
You must be signed in to change notification settings - Fork 525
Description
Description
After upgrading from draper 4.0.2 to 4.0.3, CollectionDecorator#object returns an Array instead of ActiveRecord::Relation. This breaks code that calls ActiveRecord scopes on object within CollectionDecorator.
Steps to Reproduce
# Model
class Comment < ApplicationRecord
scope :recent, -> { order(created_at: :desc) }
scope :published, -> { where(published: true) }
end
# CollectionDecorator
class CommentsDecorator < Draper::CollectionDecorator
def recent_published
object.recent.published
end
end
# Usage
post.comments.decorate.recent_publishedExpected Behavior (4.0.2)
object is an ActiveRecord::Relation, so calling scopes like recent works correctly.
Actual Behavior (4.0.3+)
object is an Array, so calling scopes raises NoMethodError:
NoMethodError: undefined method `recent' for an instance of Array
Root Cause
This appears to be caused by PR #932, which introduced CollectionProxy#decorate:
# lib/draper/decoratable/collection_proxy.rb
def decorate(options = {})
decorator_class.decorate_collection(load_target, options.reverse_merge(with: nil))
endload_target returns the cached association records as an Array, not the original ActiveRecord::Relation.
While this change improves performance by avoiding redundant database queries, it's a breaking change for code that relies on calling ActiveRecord methods on object.
Environment
- draper version: 4.0.3+ (works in 4.0.2)
- Ruby version: 3.3.7
- Rails version: 7.1.6
Possible Solutions
- Document this as a breaking change
- Provide an option to preserve the original Relation
- Add method_missing to delegate unknown methods to the original relation (if stored separately)
Workaround
Currently pinning draper to version 4.0.2.