'Rails - how to access ActionDispatch UploadedFile default attributes in my methods?
I'm new to rails and building a simple bank statement converter app. User would select bank name, upload their statement, click "convert", and the converted file will be automatically downloaded.
How to access Rails ActionDispatch::::Http::UploadedFile attributes, in particular the content_type
attribute, in the controller? I would like to check for correct file type before passing the file for futher processing in the models by using that attribute in my validation methods.
I tried .content_type
and [:content_type]
, none worked, resulting in NoMethodError
even though the method is clearly defined as private method in the controller.
Here's my current application setup:
in the webpage, a form would allow user to submit
:bank
and:statement
params.in
ConvertersController
, the params are secured using the privateconverter_params
method, resulting in the following full params (as captured in server log):
Parameters: {"authenticity_token"=>"[FILTERED]", "converter"=>{"bank"=>"bank1", "statement"=>#<ActionDispatch::Http::UploadedFile:0x000055d9699140e0 @tempfile=#<Tempfile:/tmp/RackMultipart20210401-31472-dvsdde.pdf>, @original_filename="bank1.pdf", @content_type="application/pdf", @headers="Content-Disposition: form-data; name=\"converter[statement]\"; filename=\"bank1.pdf\"\r\nContent-Type: application/pdf\r\n">}, "commit"=>"convert"}
- Then in
:create
action, I appliedfile_check
private method onto the uploaded statement (i.e.converter_params[:statement]
) to check whether the file type is correct:
ConvertersController < ApplicationController
.
.
.
def create
@converter = Converter.new(converter_params)
if converter_params[:statement].nil?
flash.now[:alert] = "Error: no statement provided"
render action: "index"
elsif converter_params[:statement].file_check
flash.now[:alert] = "Error: wrong file type"
render action: "index"
else
result = @converter.run_conversion
file_path = Rails.root.join('public', 'output', result)
stream_then_delete_statement(file_path)
end
end
.
.
.
private
def converter_params
params.require(:converter).permit(:bank, :statement)
end
def file_check
pdf_statement = [ "bank1" ]
csv_statement = [ "bank2" ]
if pdf_statement.include? converter_params[:bank]
self.content_type.pdf_check?
elsif csv_statement.include? converter_params[:bank]
self.content_type.csv_check?
else
exit(0)
end
end
.
.
.
end
- then in the model, there are
csv_check?
andpdf_check?
methods that thefile_check
private method is referring to:
class MyModel < ActiveRecord::Base
def pdf_check?
self == "application/pdf"
end
def csv_check?
self == "application/csv"
end
.
.
.
end
However, currently I got NoMethodError
, even though the file_check
method is clearly defined as private method at the ConvertersController
. This error baffles me, as other private methods such as stream_then_delete_statement
is working normally.
full error:
NoMethodError in ConvertersController#create
undefined method `file_check' for #<ActionDispatch::Http::UploadedFile:0x000055d9699140e0 @tempfile=#<Tempfile:/tmp/RackMultipart20210401-31472-dvsdde.pdf>, @original_filename="bank1.pdf", @content_type="application/pdf", @headers="Content-Disposition: form-data; name=\"converter[statement]\"; filename=\"bank1.pdf\"\r\nContent-Type: application/pdf\r\n">
Solution 1:[1]
You have defined the method file_check
in class ConvertersController
but calling it using an instance of class ActionDispatch::Http::UploadedFile
.
Your error message says:
undefined method `file_check' for #<ActionDispatch::Http::UploadedFile:0x000055d9699140e0 @tempfile=#<Tempfile:/tmp/RackMultipart20210401-31472-dvsdde.pdf>, @original_filename="bank1.pdf", @content_type="application/pdf", @headers="Content-Disposition: form-data; name=\"converter[statement]\"; filename=\"bank1.pdf\"\r\nContent-Type: application/pdf\r\n">
This means its trying to call the method file_check on an object of class ActionDispatch::Http::UploadedFile
but couldn't find one.
You should call the method directly and pass the statement params as an argument to the method:
elsif file_check(converter_params[:statement])
.
.
.
def file_check(statement_params)
.
.
.
end
You can find the current object by calling self
. Try using a debugger like byebug https://github.com/deivid-rodriguez/byebug to check it.
Solution 2:[2]
The initialize method for ActionDispatch::Http::UploadedFile
is expecting hash[:type]
and not hash[:content_type]
.
The ruby documentation is not clear on this point.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Ro55 |