File upload won't work in Ruby on Rails 3 usin

2019-08-22 15:48发布

问题:

I have a very simple configuration for uploading files. I simply want to upload an image to a database (I know, I know...) with a description. That's it.

Here is what my model looks like (which I learned from here). Basically, it is exactly the way the example is setup, only with the attr_protected line to work Rails 3.2:

Photo < ActiveRecord::Base
  # note: there is also a :description attribute!!
  attr_protected :file_name, :content_type, :binary_data
  def image_file=(input_data)
    self.file_name input_data.original_filename
    self.content_type = input_data.content_type.chomp
    self.binary_data = input_data.read
  end
end

Here is what my very simple view looks like:

<h1>New Photo</h1>

<%= form_for(@photo) do |f| %>

  <fieldset>
    <legend>Upload a Photo</legend>

    <div class="control-group">
      <label class="control-label">Photo</label>
      <div class="controls">
        <%= f.file_field :image_file %>
      </div>
    </div>

    <div class="control-group">
      <%= f.label :description, class: "control-label" %>
      <div class="controls">
        <%= f.text_field :description, class: "text_field" %>
      </div>
    </div>

    <div class="form-actions">
      <%= f.submit "Upload", class: "btn btn-primary" %>
      <%= link_to "Cancel", photos_path, class: "btn" %>
    </div>
  </fieldset>

<% end %>

And finally (merely for completeness), here is my Create action (simple scaffolding):

def create
  @photo = Photo.new(params[:photo])

  respond_to do |format|
    if @photo.save
      format.html { redirect_to @photo, notice: 'Photo was successfully created.' }
      format.json { render json: @photo, status: :created, location: @photo }
    else
      format.html { render action: "new" }
      format.json { render json: @photo.errors, status: :unprocessable_entity }
    end
  end
end

The idea is that the user will choose a file and type a small description which should post to a 'Create' method on the /photos controller. Unfortunately when I click the submit button I get a very vague error that doesn't give me information about what the real problem is:

ArgumentError in PhotosController#create

wrong number of arguments (1 for 0)
Rails.root: /Users/me/dev/photo-app

Application Trace | Framework Trace | Full Trace
app/models/photo.rb:4:in `image_file='
app/controllers/photos_controller.rb:43:in `new'
app/controllers/photos_controller.rb:43:in `create'
Request

Parameters:

{"utf8"=>"✓",
 "authenticity_token"=>"qSjMHgjCDo2ORmTvnujrljfPCj6oekLI9KAz4x5gA7Q=",
 "photo"=>{"image_file"=>#<ActionDispatch::Http::UploadedFile:0x00000101726fd0 @original_filename="SomePic.jpg",
 @content_type="image/jpeg",
 @headers="Content-Disposition: form-data; name=\"photo[image_file]\"; filename=\"SomePic.jpg\"\r\nContent-Type: image/jpeg\r\n",
 @tempfile=#<File:/var/folders/kc/8hsmx29j3xn2_j_9tsw8bz6w0000gn/T/RackMultipart20121001-52387-lre7zh>>,
 "description"=>"my description"},
 "commit"=>"Upload"}

I've looked all over Google and StackOverflow, but nothing seems to match my (very simple) example. Any help would be greatly appreciated!

Thanks in advance!

回答1:

Here, image_file only contains the ActionDispatch object and not the content and description of the file as stated by :

"image_file" => #<ActionDispatch::Http::UploadedFile:0x00000101726fd0 original_filename="SomePic.jpg"

This looks absurd way of uploading a file. Either way, you will have to write content to your uploading location by reading :tempfile



回答2:

I took @kiddorails advice and implemented CarrierWave along with the Amazon Web Service. My project required image uploads and I was limited to Heroku. Therefore, I dove in and figured it out. In hind sight, it's the best solution, but at the time it seemed overkill for my (sample) project application. It was tricky for me (as a 'non-Ruby on Rails' developer).

At the end of the day, I would recommend anybody else who wishes to store images into a database to NOT do that, and do the same thing I did. Learn the right way to do it. :)