mime-types/ruby-mime-types

MIME::Types#type_for doesn't find an extension added with MIME::Type#add_extensions

Ddam opened this issue · 11 comments

Ddam commented

I need to add an extension to the existing mime type application/octet-stream.
I tried doing this:

MIME::Types["application/octet-stream"].first.add_extensions("mo")
MIME::Types.of('filename.mo').first.to_s # => returns ""

When looking at the code, it seems that the variable @extension_index is not refreshed.
I also tried calling index_extensions after adding the new extension: it works, but is deprecated.

I need to think about how to do this, but it is a bug.

I see in the History.rdoc that this deprecation happened in 2013, but I don't see the reasoning behind the API change. Any insight on why it was deprecated?

@mehulkar it’s something that should not be worried about by the consumer of the library. I just need to figure out how to hook this in. I don’t think I can fix this until 3.x when a feature introduced in an upcoming release becomes default behaviour.

I see, thanks for the response @halostatue.

I use index_extensions to add custom file extensions for mime types. If I don't have these extensions added to the mime types, then paperclip (ruby library for image uploading/processing) fails spoof detection and I have to disable. I'm not clear on if there's a different way I should be matching up file types and extensions now?

What I’m saying is that #index_extensions is not something you should have to call. Adding a new mime type, or updating a mime type in a registry should reindex the extensions for that registry. That is:

MIME::Types["application/octet-stream"].first.add_extensions("mo")
MIME::Types.index_extensions
MIME::Types.of('filename.mo').first.to_s # => returns "application/octet-stream"

should be:

MIME::Types["application/octet-stream"].first.add_extensions("mo")
MIME::Types.of('filename.mo').first.to_s # => returns "application/octet-stream"

That it isn’t is a bug. Right now, MIME::Types don’t known anything about the container(s) that they belong to. With the columnar store implementation we are creating is that knowledge, but I’m not hooking this particular behaviour in place quite yet (because extensions are loaded first).

I prefer not leaving this bug in place, but I don’t have a good way to do this that doesn’t potentially result in cyclical dependencies or use a potentially unsafe weak reference or add an external dependency. I will figure it out for 3.0.

Didn’t mean to close this one with the release.

Do you think we can add a new public method to MIME::Types for this? Something like:

class MIME::Types
  def add_type_extensions(type_id, *extensions)
    type = self[type_id]
    type.add_extensions(*extensions)
    index_extensions!(type)
  end
end

I'd be happy to write the tests and submit a PR.

We could also possibly make a MIME::Type keep track of all the MIME::Types it's been added to and call index_extensions on each one of those when adding extensions to a type.

We could also have a configure method that accepts a block wherein types and extensions can be added and have all the caches updated after executing the block.

Just throwing out these ideas here. :-) BTW, thanks for all your work on this gem!

I don’t see it happening in the 2.x release, and that API isn’t what I would want for this. Basically, that has the problem that MIME::Types['application/word'] returns two items…and that the more I look at it, #priority_sort is sorting on the wrong thing first (it uses the simplified type—another design problem now that the x- prefix has been retired)…

Basically, there will be one of two ways that this works:

  1. add_type Just Works for MIME::Types that are put into a registry. This is preferred, but will require that I understand how WeakRef works and/or add a dependency on ref to get this right.
  2. Alternatively, there is a #change_type method that encapsulates the workflow, outlined in your proposed mechanism, but does does it through some sort of temporary proxy object (e.g., #change_type(type) { |type| type.add_extensions(…) }).

Those are the main methods I’m considering, but they are all bigger changes than I am comfortable with for 2.x. One of the nice things that I will have is that I’m probably going to drop Ruby 1.9 support with mime-types 3.