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

北战南征 提交于 2019-12-09 04:19:50

问题


Background: I have a Book model with a cover_file attribute that gets set with an uploaded file via one of my Rails controllers. I'm using Rails v4.0.4.

Goal: I want to test that only files with certain content types get saved. I plan to create Rspec test examples with ActionDispatch::Http:UploadedFile objects set with different content_type attributes.

Problem: When I initialize a new ActionDispatch::Http::UploadedFile with a content_type, it doesn't seem to get set (see test & output below that confirms that it's nil). It seems that I can only set it with a setter AFTER the UploadedFile has been initialized. I don't see any mention of this behavior in the docs nor could I find a similar Q&A on SO, so I'd appreciate anyone's help in determine what I'm doing wrong. Thanks!

Code:

describe Book do
  let(:book) {FactoryGirl.build(:book)}
  describe "Save" do
    context "with valid data" do
      before do
        cover_image = File.new(Rails.root + 'spec/fixtures/images/cover_valid.jpg')
        book.cover_file = ActionDispatch::Http::UploadedFile.new(tempfile: cover_image, filename: File.basename(cover_image), content_type: "image/jpeg")
        puts book.cover_file.content_type.nil?
        book.cover_file.content_type = "image/jpeg"
        puts book.cover_file.content_type
      end
      specify{expect(book.save).to be_true}
    end
  end
end

Output:

true
image/jpeg

回答1:


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


来源:https://stackoverflow.com/questions/23899860/actiondispatchhttpuploadedfile-content-type-not-being-initialized-in-rspec-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!