Why do I get an InvalidSignature error when uploading multiple images? - ruby-on-rails

I'm new to Rails and I'm trying to save multiple images that come from the front end using a Rails API. I did the ActiveStorage migration but it still gives me the error.
Error:
ActiveSupport: :MessageVerifier::InvalidSignature (ActiveSupport: :MessageVerifier: :InvalidSignature):
app/controllers/posts_controller.rb:20:in ‘create'
Started POST "“/posts" for 172.19.0.1 at 2021-08-05 11:28:13 +0000
Processing by PostsController#create as HTML
Parameters: {"post"=>{"type_id"=>"1", "title"=>"test", "location"=>"calmo", "“category"=>"New Company", "“description"=>"", “images"=>["[object File],[object File],[object File],[
object File]"], "“start_date"=>"2010-03-02", "“end_date"=>"2011-03-02", "“start_time"=>"14:50", "end_time"=>"14:53"}}
User Load (1.0ms) [{"id", 3], ["LIMIT", 1]]
Completed 500 Internal Server Error in 21ms (ActiveRecord: 8.0ms | Allocations: 3822)
server side error
Post.rb
class Post < ApplicationRecord
belongs_to :user
has_many_attached :images
end
posts_controller.rb
def post_params
params.require(:post).permit(:type_id, :category, :title, :location, :description,
:start_date, :end_date, :start_time, :end_time, images: [])
end
index.js
const handleSubmit = (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('post[type_id]', data.type);
formData.append('post[title]', data.title);
formData.append('post[location]', data.location);
formData.append('post[category]', data.category);
formData.append('post[description]', data.description);
formData.append('post[images][]', data.images);
formData.append('post[start_date]', data.startDate);
formData.append('post[end_date]', data.endDate);
formData.append('post[start_time]', data.startTime);
formData.append('post[end_time]', data.endTime);
post(formData, '/posts', function (response) {
alert(response.data);
});
};

Might be a bit late but I had the same problem today and came across this post. Later I figured it out. I did a loop through the images.
Like you, I had like this (using your code above as an example):
formData.append('post[images][]', data.images);
And I kept getting the InvalidSignature error from Rails 7. Then I decided to do a loop:
for (let i = 0; i < data.images.length; i++) {
formData.append('post[images][]', data.images[i]);
}
and the problem was solved for me.

Related

A workaround to pre-populate file_field?

I don't think you can literally pre-populate the file_field so I've been struggling with a workaround for the same end goal, which is to take an image already uploaded to the application via User A and then for User B to be able to save that same image as his own too, similar to pinterest.
This is what I've tried:
index
<%= link_to new_inspiration_path(inspiration_image: inspiration.image) %>
controller
def new
#inspiration = current_user.inspirations.build
#inspiration.image = URI.parse(params[:inspiration_image])
end
server
Started GET "/inspirations/new?inspiration_image=%2Fsystem%2Finspirations%2Fimages%2F000%2F000%2F069%2Foriginal%2Frule_1.jpg%3F1478260961" for 127.0.0.1 at 2016-11-04 08:10:41 -0400
Processing by InspirationsController#new as */*
Parameters: {"inspiration_image"=>"/system/inspirations/images/000/000/069/original/rule_1.jpg?1478260961"} # For example, this is the image url I'm trying to duplicate for User B
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 129]]
Inspiration Load (0.4ms) SELECT "inspirations".* FROM "inspirations" WHERE "inspirations"."id" IS NULL LIMIT 1
Completed 400 Bad Request in 6ms
_form
<%= simple_form_for(#inspiration, html: { data: { modal: true } }) do |f| %>
<%= image_tag #inspiration.image.url if #inspiration.image.present? %> # I get error: ActionController::ParameterMissing (param is missing or the value is empty: inspiration):
<%= f.file_field :image %>
<% end %>
model
class Inspiration < ActiveRecord::Base
has_attached_file :image, :styles => { :medium => "300x300>", :small => "150x150>" }
validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
belongs_to :user
def image_remote_url=(url_value)
self.image = URI.parse(url_value).to_s unless url_value.blank?
super
end
end
Change #inspiration.image assignment to #inspiration.image = URI.parse(params[:inspiration_image])
More info can be found here: https://github.com/thoughtbot/paperclip/wiki/Attachment-downloaded-from-a-URL
EDIT:
Change model according to the info in the link:
attr_reader :image_remote_url
#image_remote_url = url_value
Remove super call
Change assignment to #inspiration.image_remote_url = params[:inspiration_image]

Paperclip image upload (base64) - getting 500 internal server error (undefined method 'permit')

I'm trying to upload an image using Paperclip; I followed the paperclip quick start guide as closely as possible, but I'm doing something wrong and can't find out what. I'm new to Ruby and Rails; the whole project is set up with the AngularJS framework.
What I'm doing is sending a POST request that contains a base64 encoded image:
DataService.add("uploads", {image: file}) [...]
The service looks like this:
add: function(type, object) {
return $http.post(API_URL + "/" + type, object) [...]
"file" is the base64 encoded image; I hope it is somewhat clear how the POST works. Now the backend:
Controller:
module Api
class UploadsController < ApplicationController
# POST api/uploads
def create
p params
#upload = Upload.create(upload_params)
#upload.save
end
private
def upload_params
params.require(:upload).permit(:image)
end
end
end
Model:
class Upload < ActiveRecord::Base
attr_accessor :content_type, :original_filename, :image_data
before_save :decode_base64_image
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/storage/images/:style/missing.png", :url => "/:class/:attachment/:id/:style_:basename.:extension"
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
validates :image, :attachment_presence => true
# validates_attachment :image, :size => { :in => 0..100.kilobytes }
protected
def decode_base64_image
if image_data && content_type && original_filename
decoded_data = Base64.decode64(image_data)
data = StringIO.new(decoded_data)
data.class_eval do
attr_accessor :content_type, :original_filename
end
data.content_type = content_type
data.original_filename = File.basename(original_filename)
self.image = data
end
end
end
That's basically it - I hope I included everything that's important for my problem (first question here).
When testing this with a simple image I get a 500 - Internal server error, with request payload
{"image":"data:image/png;base64,...<base64 code>...}
I understand that the mistake is most likely in the controller/model part, but I don't know how to solve this.
Thanks for your help :)
EDIT:
When testing this locally with Postman (form-data, POST, Key: upload and an image) I get this:
Started POST "/api/uploads" for 127.0.0.1 at 2015-06-13 16:34:08 +0200
Processing by Api::UploadsController#create as */*
Parameters: {"upload"=>#<ActionDispatch::Http::UploadedFile:0x00000002f0e108 #tempfile=# <Tempfile:/tmp/RackMultipart20150613-7296-8zu01e.jpeg>, #original_filename="meise.jpeg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"upload\"; filename=\"meise.jpeg\"\r\nContent-Type: image/jpeg\r\n">}
{"upload"=>#<ActionDispatch::Http::UploadedFile:0x00000002f0e108 #tempfile=#<Tempfile:/tmp/RackMultipart20150613-7296-8zu01e.jpeg>, #original_filename="meise.jpeg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"upload\"; filename=\"meise.jpeg\"\r\nContent-Type: image/jpeg\r\n">, "controller"=>"api/uploads", "action"=>"create"}
Completed 500 Internal Server Error in 0ms
NoMethodError (undefined method `permit' for # <ActionDispatch::Http::UploadedFile:0x00000002f0e108>):
app/controllers/api/uploads_controller.rb:16:in `upload_params'
app/controllers/api/uploads_controller.rb:7:in `create'
EDIT 2:
It works now, but for everyone with the same problem: if you're sending the base64 encoded image like I'm doing it in the DataService and having the same controller/module setup, it will work with Paperclip, but not with the frontend. In
has_attached_file :image, :styles => { :medium => "1000x1000>", :thumb => "150x150#" }, :default_url => "/storage/images/:style/missing.png", :url => "/:class/:attachment/:id/:style_:basename.:extension"
I had to change the last part to
"/:class/:attachment/:id/:style_image_:id.png"
Because somehow the name and extension got lost somewhere. I used the id as the file name now, and .png as an extension because the base64 is created from a png that I created in the frontend.
The problem is with this line:
params.require(:upload).permit(:image)
require ensures that a parameter is present. If it's present, returns the parameter at the given key. In your case it is returning ActionDispatch::Http::UploadedFile object which doesn't have permit method.
You can solve this by removing require and passing the file in image parameter instead of upload:
params.permit(:image)
If you want to keep the existing code, have the client pass the image in a field with name upload['image']
In Rails log, it should be like
Parameters: {"upload"=> { "image" =>#<ActionDispatch::Http::UploadedFile:0x00000002f0e108 #tempfile=# .....}}
Notice how image is inside upload.

Paperclip: Content Type Spoof trying to upload .gpx files

Apologies if this has been answered and I failed to find it. Any direction would be greatly appreciated.
Using Rails 4.1.4, Paperclip 4.2.0 and Simple Form 3.0.2.
After Submit, I get has an extension that does not match its contents output in the form error message.
In the server window:
Started POST "/routes" for 127.0.0.1 at 2014-08-28 15:18:25 +0700
Processing by RoutesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"5BCHGBkwQH4mlnTVjy/PpD53mJKJpSmBXwXT/oul7yY=", "route"=>{"track_attributes"=>{"gpx"=>#<ActionDispatch::Http::UploadedFile:0x007fa89c9cd348 #tempfile=#<Tempfile:/var/folders/_g/6shs5yrj36n960wpt880ysl80000gn/T/RackMultipart20140828-42106-vi71nb>, #original_filename="Serge's tracks.gpx", #content_type="application/octet-stream", #headers="Content-Disposition: form-data; name=\"route[track_attributes][gpx]\"; filename=\"Serge's tracks.gpx\"\r\nContent-Type: application/octet-stream\r\n">}, "title"=>"Serge track", "description"=>"loop of hang dong", "distance"=>"", "total_ascent"=>""}, "commit"=>"Create Route"}
Command :: file -b --mime '/var/folders/_g/6shs5yrj36n960wpt880ysl80000gn/T/f55fe48e09c9cc3ee6c6271fe94f407520140828-42106-1hgpby7.gpx'
[paperclip] Content Type Spoof: Filename Serge's_tracks.gpx ([]), content type discovered from file command: application/xml. See documentation to allow this combination.
(0.3ms) BEGIN
Command :: file -b --mime '/var/folders/_g/6shs5yrj36n960wpt880ysl80000gn/T/f55fe48e09c9cc3ee6c6271fe94f407520140828-42106-62bkvh.gpx'
[paperclip] Content Type Spoof: Filename Serge's_tracks.gpx ([]), content type discovered from file command: application/xml. See documentation to allow this combination.
(0.8ms) ROLLBACK
I haven't been able to find said documentation in the Paperclip docs.
Running file Serge\'s\ tracks.gpx --mime-type -b produces application/xml
My MVC looks like this:
class Track < ActiveRecord::Base
belongs_to :route
has_attached_file :gpx
validates_attachment_content_type :gpx, :content_type => /application\/xml/
end
class Route < ActiveRecord::Base
has_one :track, dependent: :destroy
accepts_nested_attributes_for :track
validates :title, presence: true
end
Inside RoutesController
def new
#route = Route.new
#route.track = Track.new
end
def create
#route = Route.new(route_params)
end
def route_params
params.require(:route).permit(:title, :description, :distance, :total_ascent, track_attributes: [:gpx])
end
The simple_form:
= simple_form_for #route do |r|
= r.simple_fields_for :track do |t|
= t.input :gpx
= r.input :title
= r.input :description
= r.input :distance
= r.input :total_ascent
= r.button :submit
As mentioned in this post: Paperclip gem spoofing error? and this article http://robots.thoughtbot.com/prevent-spoofing-with-paperclip, the problem was solved by apparently bypassing the command file -b --mime-type that is called by Paperclip.
To do this I created a paperclip.rb file in config/initializers.
Paperclip.options[:content_type_mappings] = {
:gpx => 'application/xml'
}
While the problem is solved, I am still confused as to why the problem existed when the file command was returning a correct result, and also curious where the #content_type="application/octet-stream" in the params is coming from.

Rails strange behavior of production app running on heroku

In user model I've got attribute location of type point. Now I've got a validation code:
validates :location, :format => { :with => /\(-?\d+(?:\.\d+)?,-?\d(?:\.\d+)?\)/,
:on => :update,
:if => :location_changed? }
It works fine in console, on localhost, but on heroku it returns:
Processing by UsersController#update as / 2012-07-31T18:14:37+00:00
app[web.1]: Parameters:
{"user"=>{"location"=>"(3.545452,2.4353534)"}, "id"=>"self"}
2012-07-31T18:14:37+00:00 app[web.1]: Completed 500 Internal Server
Error in 13ms 2012-07-31T18:14:37+00:00 app[web.1]:
2012-07-31T18:14:37+00:00 app[web.1]: NoMethodError (undefined method
location_changed?' for #<User:0x00000004dc29c8>):
2012-07-31T18:14:37+00:00 app[web.1]:
app/controllers/users_controller.rb:16:inupdate'
Actually it works also great in heroku console, but don't work in curl request.
Rails version 3.2.7.
attr_accessible :profile_picture, :password, :location
Thanks!
It looks like a magic. I fixed it with recreation if table and server restart. Very strange.

paperclip + vestal_versions problem

I need help to setup paperclip with vestal_versions. I followed this tutorial
http://blog.dmfranc.com/post/1036667709/paperclip-and-vestal-versions
But when i try to upload files, i get this error
[paperclip] Saving attachments.
Completed 500 Internal Server Error in 626ms
NoMethodError (undefined method `version' for #):
my file model are a belongs_to from the buildings and building has_menu building_pdf.
class BuildingPdf < ActiveRecord::Base
belongs_to :building
has_attached_file :pdf, :keep_old_files => true, :url => "/pdf/:id/versions/:version/:basename.:extension",
:path => ":rails_root/system/pdf/:id/:version/:basename.:extension"
Paperclip.interpolates :version do |attachment, style|
attachment.instance.version.to_s
end
end
here is my /lib/initializers/versioning_with_paperclip.rb
module Paperclip
class Attachment
def save
flush_deletes unless #options[:keep_old_files]
flush_writes
#dirty = false
true
end
end
end
what else i missing?
thanks.
PS. After i added versioning in my model i get this error
[paperclip] Saving attachments.
Completed 500 Internal Server Error in 1512ms
Mysql2::Error (Table 'db.versions' doesn't exist):
app/models/building_pdf.rb:10:in `version'
config/initializers/versioning_with_paperclip.rb:5:in `save'
You need to add (versioned) to your model
class BuildingPdf < ActiveRecord::Base
versioned
..
end

Resources