Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monkey patching ActiveStorage::Attachment gets lost

So I decided to add an url attr_accessor to ActiveStorage::Attachment objects.

In development the patch holds for a while until it seems to "have been lost". Meaning it works for few minutes, then it does not work anymore. Then I need to restart the server in order to get the patch applied again. I believe I am not patching correctly and I would need advises in that mater.


Here is what I tried:

lib/ext/active_storage/attachment.rb

First try :

module ActiveStorageUrl
  extend ActiveSupport::Concern

  included do
    attr_accessor :url
  end
end

ActiveStorage::Attachment.send :include, ActiveStorageUrl

Second try

class ActiveStorage::Attachment < ActiveRecord::Base
  attr_accessor :url
end

And by the way in both case it's loaded with this:

config/initializers/monkey_patches.rb

require 'ext/active_storage/attachment'

So when it work I have no error message, but after a while the patch "diseapear" (lacking better terms), and I get the following error, telling me my attr_accessor is not there anymore. Rails must have reloaded ActiveStorage classes and my patch is lost.

Module::DelegationError in Products#images
url delegated to blob, but blob is nil
like image 498
Benj Avatar asked Mar 11 '19 20:03

Benj


People also ask

How does monkey patching work?

Monkey patching is reopening the existing classes or methods in class at runtime and changing the behavior, which should be used cautiously, or you should use it only when you really need to. As Python is a dynamic programming language, Classes are mutable so you can reopen them and modify or even replace them.

What is class monkey patching?

Monkey patching is a technique used to dynamically update the behavior of a piece of code at run-time. A monkey patch (also spelled monkey-patch, MonkeyPatch) is a way to extend or modify the runtime code of dynamic languages (e.g. Smalltalk, JavaScript, Objective-C, Ruby, Perl, Python, Groovy, etc.)


3 Answers

I placed my ActiveStorage::AttachmentMonkeyPatch in /app/models/active_storage/
I've added a callback to get informed if the Attachment has changed. It works fine, all the time.

Maybe this is the issue.

like image 73
Archer Avatar answered Nov 15 '22 20:11

Archer


You are probably losing your monkey patch because the code gets reloaded and your ext/active_storage/attachment isn't re-required.

You can tell Rails to run a callback at startup and every time code is reloaded like this.

Rails.configuration.to_prepare do
  require 'ext/active_storage/attachment'
end
like image 41
afrase Avatar answered Nov 15 '22 19:11

afrase


Seems to have to do with delegate_missing_to, e.g.

delegate_missing_to :blob

https://github.com/rails/rails/blob/master/activestorage/app/models/active_storage/attachment.rb#L14

Going to where it's defined:

Anyway it might have to do with how attr_accessor works, I would try:

def url
  @url
end

def url=(url)
  @url = url
end

Instead of attr_accessor (which is a C function actually).

Otherwise a really really hacky way to solve this would be to check for ActiveStorage::Attachment.instance_methods.include?(:url) and monkey patch / include / prepend when not present.

like image 26
localhostdotdev Avatar answered Nov 15 '22 19:11

localhostdotdev