rails icon indicating copy to clipboard operation
rails copied to clipboard

Use `class_attribute` transform block for job config

Open jonathanhefner opened this issue 1 year ago • 1 comments

In #45476, ActiveRecord::Base.destroy_association_async_job was made to accept a string which would be lazily constantized, to avoid loading ActiveJob::Base too soon. However, due to the way class_attribute values are written, each subclass calling destroy_association_async_job will allocate a _destroy_association_async_job singleton method regardless of whether the subclass assigns a custom job value.

Additionally, class_attribute requires using a dummy attribute name so that the post-processing reader method is not overwritten when the attribute is set. This is particularly cumbersome when instance accessors are involved.

This PR re-implements #45476 by adding support for a transform block to class_attribute. A transform block is applied to an attribute value when that value is first read, and the result is memoized as the actual value of the attribute. Thus, using a transform block, destroy_association_async_job can lazily constantize and memoize the result, without allocating additional singleton methods, and without juggling attribute names.

The PR also applies the same technique to ActionMailer::Base.delivery_job. Closes #45486.

I wrote about a few of the alternatives I considered in #45603. Closes #45603.

jonathanhefner avatar Jul 18 '22 20:07 jonathanhefner

This is a nice find, and I agree it should be fixed. However I don't think adding this extra feature to class_attributes is the way to go. Its semantic is already quite complex and I'd rather avoid to complexify it.

Could we instead to this as an eager_load callback? We could walk down the inheritance tree and resolve the classes as needed.

What do you think?

byroot avatar Jul 28 '22 06:07 byroot