Actiondispatch::Http::Uploadedfile.Content_Type Not Being Initialized in Rspec Test

ActionDispatch::Http::UploadedFile.content_type not being initialized in Rspec test

I looked at the Rails source file for the UploadedFile class and I found the issue. For the @content_type attribute, for example, while the getter and setters are named as expected (.content_type), the initialize method looks for an attribute called type in the options hash. The same thing happens for @original_filename; initialize looks for filename instead of original_filename. This seems to have been the case since the Rails 3 codebase.

So, if I change my code above to the following, everything works as expected:

book.cover_file = ActionDispatch::Http::UploadedFile.new(tempfile: cover_image, filename: File.basename(cover_image), type: "image/jpeg")

Relevant section of rails/actionpack/lib/action_dispatch/http/upload.rb...

class UploadedFile
# The basename of the file in the client.
attr_accessor :original_filename

# A string with the MIME type of the file.
attr_accessor :content_type

# A +Tempfile+ object with the actual uploaded file. Note that some of
# its interface is available directly.
attr_accessor :tempfile
alias :to_io :tempfile

# A string with the headers of the multipart request.
attr_accessor :headers

def initialize(hash) # :nodoc:
@tempfile = hash[:tempfile]
raise(ArgumentError, ':tempfile is required') unless @tempfile

@original_filename = encode_filename(hash[:filename])
@content_type = hash[:type]
@headers = hash[:head]
end

Testing POST ActionDispatch::Http::Parameters::ParseError: 765

Removing the 'Content-Type' => 'application/json' solved the problem.

Finally remembered that ActionDispatch uses the headers to know how to parse the params. 'Content-Type' => 'application/json' is a standard piece of boilerplate that's ok to throw around with GET requests and query params but not with POST when used this way.

Reading and writing file attributes

It's not documented (and doesn't make much sense), but it looks like the options UploadedFile#initialize takes are :tempfile, :filename, :type and :head:

def initialize(hash) # :nodoc:
@tempfile = hash[:tempfile]
raise(ArgumentError, ':tempfile is required') unless @tempfile

@original_filename = encode_filename(hash[:filename])
@content_type = hash[:type]
@headers = hash[:head]
end

Changing your invocation to this ought to work:

ActionDispatch::Http::UploadedFile.new tempfile: 'tempfilefoo',
filename: 'filename_foo.jpg', type: 'content_type_foo', head: 'headers_foo'

Or you can set them after initialization:

file = ActionDispatch::Http::UploadedFile.new tempfile: 'tempfilefoo', filename: 'filename_foo.jpg'
file.content_type = 'content_type_foo'
file.headers = 'headers_foo'

I'm not sure I understand your second question, "And how can I read these attributes from a file instance?"

You can extract the filename (or last component) from any path with File.basename:

file = File.new('path/to/file.png')
File.basename(file.path) # => "file.png"

If you want to get the Content-Type that corresponds to a file extension, you can use Rails' Mime module:

type = Mime["png"] # => #<Mime::Type:... @synonyms=[], @symbol=:png, @string="text/png">
type.to_s # => "text/png"

You can put this together with File.extname, which gives you the extension:

ext = File.extname("path/to/file.png") # => ".png"
ext = ext.sub(/^\./, '') # => "png" (drop the leading dot)
Mime[ext].to_s # => "text/png"

You can see a list of all of the MIME types Rails knows about by typing Mime::SET in the Rails console, or looking at the source, which also shows you how to register other MIME types in case you're expecting other types of files.

ActiveStorage - Could not find or build blob: expected attachable, got #ActionDispatch::Http::UploadedFile

First you need to create blob file in case of active storage.

def attach_doc(doc_param)
doc = ActiveStorage::Blob.create_and_upload!(
io: doc_param,
filename: doc_param.original_filename,
content_type: doc_param.content_type
)
document = context[:current_user].documents.doc.attach(doc)
end
In rails < 7.0 method is ActiveStorage::Blob.create_after_upload


Related Topics



Leave a reply



Submit