#528·dragonfly

[breaking] ostruct dependency introduced in 1.4.1 breaks dragonfly as it has stricter handling of internals than Ruby stdlib version

Author: mrIlloCreated Jul 21, 2025Updated Jul 21, 2025

ostruct from RubyGems (like 0.6.1) is stricter than the built-in stdlib version — especially in how it handles .dup, initialize_copy, and internal coercion like to_sym. Dragonfly’s usage of OpenStruct worked fine with the stdlib version, but not with the gem version. So even though the gem was added for future Ruby 3.5 compatibility, it breaks behavior today under Ruby 3.0–3.2.

How to reproduce: It took me a whole day to narrow it down to this.

  1. I have added a processor :cropped_overlay_teaser, MyProcessor in my config
  2. class MyProcessor is the wrapper (with call(content, size) ) around Dragonfly::ImageMagick::Commands.convert(content,....)
  3. in my class PicturesApp < Dragonfly::RoutedEndpoint I do
  ...
  picture = @app.fetch_file(@fetch_file)
  picture = picture.cropped_overlay_teaser(@size)
  ...
  1. when using you get this strange error:
undefined method `to_sym' for false:FalseClass
Did you mean?  to_s
stack trace: /var/lib/gems/3.0.0/gems/ostruct-0.6.1/lib/ostruct.rb:319:in `[]='
/var/lib/gems/3.0.0/gems/ostruct-0.6.1/lib/ostruct.rb:160:in `block in update_to_values!'
/var/lib/gems/3.0.0/gems/ostruct-0.6.1/lib/ostruct.rb:159:in `each_pair'
/var/lib/gems/3.0.0/gems/ostruct-0.6.1/lib/ostruct.rb:159:in `update_to_values!'
/var/lib/gems/3.0.0/gems/ostruct-0.6.1/lib/ostruct.rb:154:in `initialize_dup'
/var/lib/gems/3.0.0/gems/dragonfly-1.4.1/lib/dragonfly/job.rb:95:in `dup'
/var/lib/gems/3.0.0/gems/dragonfly-1.4.1/lib/dragonfly/job.rb:95:in `initialize_copy'
(eval):3:in `initialize_dup'
(eval):3:in `dup'
(eval):3:in `process'
/var/lib/gems/3.0.0/gems/dragonfly-1.4.1/lib/dragonfly/app.rb:153:in `block in add_processor'
  1. in job.rb there is initialize_copy where I added debug code to show the problem:
    def initialize_copy(other)
      @steps = other.steps.map do |step|
        step.class.new(self, *step.args)
      end
      @content = other.content.dup
puts "DEBUG other.url_attributes=#{other.url_attributes.to_h}"
      @url_attributes = other.url_attributes.dup
    end
  1. with ostruct gem 0.6.x this shows you DEBUG other.url_attributes={:name=>"myfilename.jpg", false=>"myfilename.jpg"}

while with stdlib ostruct you see the expected: DEBUG other.url_attributes={:name=>"myfilename.jpg"}

  1. I could not narrow it down to why this different behavior happens, as I did not have the time to investigate when and how the internal url_attributes are set in that case.