It was right in the docs
thanks for finding
When you call open on an instance of a Pathname, it returns a new File instance for the given pathname and calls .open on that. You’ll notice if you call .object_id on the file instance, it’s returning a different object each time
irb(main):001> p = Pathname.new "Gemfile"
=> #<Pathname:Gemfile>
irb(main):002> p.open
=> #<File:Gemfile>
irb(main):003> p.open.object_id
=> 40420
irb(main):004> p.open.object_id
=> 41800
For more hacking around you can check if the object has been recycled (YMMV):
irb(main):005> ObjectSpace._id2ref(40420) # (RangeError)
irb(main):006> ObjectSpace._id2ref(41800) # (RangeError)
irb(main):007> GC.disable
=> false
irb(main):008> p.open.object_id
=> 70240
irb(main):009> ObjectSpace._id2ref(70240)
And to your point regarding:
if your Ruby program is long-running with a somehow badly optimized or misbehaving GC that never runs, you could end up with a resource leak where you run out of file descriptors because you have too many of them open. This seems to me like a cause for concern.
While you’re correct that it’s best practice to close files, I think that the (entirely subjective) counter would be that it’s a bit antithetical to Rails itself to sacrifice readability and brevity for what’s likely an unlikely and inconsequential hypothetical. I think reading the Rails Doctrine would explain some of the “why” behind this. Sure, it’s possible that a GC could be misbehaving and run out of FDs. But, that would happen 1 out of every what, billion ruby runtimes? Of all the Ruby code powering production systems as we speak, I’d argue you might expect that exact situation to happen less than a dozen times a year. Subjectively speaking, assigning the file to a variable, creating the record, and then making sure to close the file over 3 lines just isn’t as “beautiful” as inlining it (specifically wrt the documentation thing).
Of course, sometimes these decisions come to bit you in the butt! And that’s why observability and profiling are some important to a production rails application. Realistically, if the GC was having problems, ActiveRecord would exhaust all system resources before you’d expect to run out of file descriptors in a typical rails app. But at the end of the day, rails apps aren’t powering rocket ships, so the tradeoffs between potential problems versus writing conciser, prettier code is going to be different.
But, for almost 100% of rails apps
@message.images.attach(io: File.open('/path/to/file'), filename: 'file.pdf')
is preferred because it’s more “readable” than
File.open('/path/to/file') do |file|
@messages.images.attach(io: file, filename: 'file.pdf')
end
Just my thoughts though!