James N
James N

Reputation: 533

rails paperclip: param is missing or the value is empty

I am working on a rails app and making a nested resource for pictures. The model is Picture, and it is polymorphic and interacts with a couple different tables.

I am working on the controller action, and the create method. According to this answer and other things I have seen with paperclip, the params should follow the format of table_name and then file. Even when doing that, I am still getting a param is missing or the value is empty: picture error.

Here is my code:

Picture.rb

class Picture < ActiveRecord::Base
  belongs_to :imageable, polymorphic: true
  has_attached_file :image, style: { small: '64x64', medium: '100x100', large: '200x200' }
  validates_attachment :image, presence: true, content_type: { content_type: /\Aimage\/.*\Z/ },
                      size: { in: 0..5.megabytes }, default_url: 'missing_img.png'


  acts_as_list scope: [:imageable_id, :imageable_type]
end

pictures_controller.rb

class PicturesController < ApplicationController
  before_action :authorize_user!
  before_action :set_resource!

  def index
    @pictures = @resource.pictures
  end

  def create
    @picture = @resource.pictures.new(picture_params) do |pic|
      pic.imageable_type = @resource
      pic.imageable_id = @resource.id
    end
    if @picture.save
      redirect_to :back
      flash[:success] = 'Image Saved!'
    else
      redirect_to :back
      flash[:danger] = "#{@picture.errors.full_messages.to_sentence}"
    end
  end

  def destroy
    @picture = Picture.find(params[:id])
    @resource.pictures.delete(@picture)
    redirect_to :back
    flash[:success] = "Picture deleted"
  end

  private
  def set_resource!
    klass = [Gym, User, Location, Product].detect { |c| params["#{c.name.underscore}_id"] }
    @resource = klass.find(params["#{klass.name.underscore}_id"])
  end

  def picture_params
    params.require(:picture).permit(:image)
  end
end

pictures/index.html

<h6>Upload Pictures</h6>
  <%= form_for(current_user, url: url_for(controller: 'pictures', action: 'create'), method: :post, html: { multipart: true, class: 'form-horizontal' }) do |f| %>
    <%= f.file_field :image, type: :file, multiple: true, style: 'padding-bottom: 25px;' %>
    <%= f.submit "Upload", class: "btn btn-gen" %>
<% end %>

And here is the param request on form submit:

{"utf8"=>"✓",
 "authenticity_token"=>"+fsA6liECF7pkUp/0BA0wDHq9Vv63jB+WBb7O/uUEDhhmIOZ22Rb1rNWDwuwPTDPNS7jg7vP/fVCVllDV21wDw==",
 "user"=>{"image"=>[#<ActionDispatch::Http::UploadedFile:0x007f87b138acf8 @tempfile=#<Tempfile:/var/folders/9c/1_0mk00n297f560_fpv9jzl40000gn/T/RackMultipart20161020-25582-3qt3gc.jpg>,
 @original_filename="b4lROOR.jpg",
 @content_type="image/jpeg",
 @headers="Content-Disposition: form-data; name=\"user[image][]\"; filename=\"b4lROOR.jpg\"\r\nContent-Type: image/jpeg\r\n">]},
 "commit"=>"Upload",
 "user_id"=>"15"}

Even with this, I am still getting the error. Does anyone see anything wrong I'm doing in my code that I could fix? Any help is much appreciated.

Upvotes: 0

Views: 158

Answers (2)

James N
James N

Reputation: 533

I figured out a temporary work around. Definitely not ideal, and if anyone has a better suggestion I would love to hear it. But here is what I currently have that does work.

def create
  pic = nil
  if params[:user]['image']
    params[:user]['image'].each do |image|
      pic = @resource.pictures.create(image: image, imageable_type: @resource, imageable_id: @resource.id)
    end
    if pic.save
      redirect_to :back
      flash[:success] = 'Image Saved!'
    else
      redirect_to :back
      flash[:danger] = "#{pic.errors.full_messages.to_sentence}"
    end
  else
    flash[:danger] = "Picture file not found"
    redirect_to :back
  end
end

Upvotes: 0

max
max

Reputation: 102134

The problem is that your picture_params method requires the route param key picture while your form has the key user.

Lets do some refactoring:

private
  def set_resource!
    @resource = resource_class.find(params[param_key + "_id"])
  end

  def resource_class
    @resource_class ||= [Gym, User, Location, Product].detect do |c|
      params[ param_key(c) + "_id" ]
    end
  end

  def param_key(klass = resource_class)
    ActiveModel::Naming.param_key(klass)
  end

  def picture_params
    params.require(param_key).permit(:image)
  end

Instead of klass.name.underscore we use ActiveModel::Naming which is how rails figures out how to use models for stuff like routes, params or translations.

Upvotes: 1

Related Questions