Rails paperclip uploading files to Amazon S3 - ruby-on-rails

I try to upload files to Amazon S3 with paperclip gem.
The connection to S3 works fine. in the logs there is mentiond that a connection has started. (No errors in log)
in rails console got this: Completed 200 OK in 16ms (Views: 14.2ms | ActiveRecord: 1.0ms)
But in database there is nothing. And there is no files on S3.
model:
class Movie < ActiveRecord::Base
# add File to Movie association on column mo
has_attached_file :movie
# validdates the file type
validates_attachment_content_type :movie, :content_type => /\Avideo\/.*\Z/
end
controller:
class MoviesController < ActionController::Base
# Method to add a new Movie
def addMovie
if request.post?
#movie = Movie.new(movies_params)
if #movie.save
redirect_to :addMovie
end
else
#movie = Movie.new
end
end
private
def movies_params
params.require(:movie).permit(:movietitle, :movieprice, :locked, :moviedescription, :currency, :language, :movie)
end
end
LOG
Parameters: {"utf8"=>"✓", "authenticity_token"=>"DELETED", "movie"=>{"movietitle"=>"sd", "movieprice"=>"1", "currency"=>"d", "language"=>"de", "locked"=>"0", "moviedescription"=>"adasdasd", "movie"=>#<ActionDispatch::Http::UploadedFile:0x00000003e14e68 #tempfile=#<Tempfile:/tmp/RackMultipart20151226-2017-u9g0ym.mp4>, #original_filename="2015-11-14 11.51.27.mp4", #content_type="video/mp4", #headers="Content-Disposition: form-data; name=\"movie[movie]\"; filename=\"2015-11-14 11.51.27.mp4\"\r\nContent-Type: video/mp4\r\n">}, "commit"=>"Save Movie"}

Related

why does active storage throw this error: undefined method `upload' for nil:NilClass, when object is not nil

I've setup active storage on a rails project. I continuously get the error:
undefined method 'upload' for nil:NilClass.
Here is what I've done.
I've ran the migration: rails active_storage:install
I've edited my development environtment file: config.active_storage.service = :local
Same with my production file: config.active_storage.service = :amazon
Ive made sure that my model is setup correctly with has_one_attached :image
My Controller:
class EventsController < ApplicationController
def create
#event = Event.new(event_params)
#event.save
end
private
def event_params
params.require(:event).permit(:name, :image)
end
end
Here is the form:
<%= simple_form_for(#event, url: events_path, method: :post) do |f| %>
<%= f.input :name %>
<%= f.input :image %>
<%= f.submit %>
<% end %>
Here is the model:
class Event < ActiveRecord::Base
has_one_attached :image
acts_as_list
end
It might be worth mentioning that I'm upgrading this particular project to rails 5. It also used to use paperclip.
The Problem:
When I submit this form, the aforementioned error is thrown. The same
error occurs when trying to update an #event object.
UPDATES
when looking through framework trace, the error is being thrown on this line: blob.upload io. Whats weird is that when I debug this line, blob is not nil. It holds an ActiveStorage::Blob which doesn't have an id. And io is not nil either.
Error Logs:
I've taken out authenticity token purposely.
Started POST "/events" for ::1 at 2018-08-23 10:02:25 -0600
Processing by EventsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"*****************", "event"=>{"name"=>"test event", "image"=>#<ActionDispatch::Http::UploadedFile:0x00007fc816e90af8 #tempfile=#<Tempfile:/var/folders/f9/q3x5477d1dxd7fxjbrl2tvch0000gn/T/RackMultipart20180823-61111-14dih2d.jpg>, #original_filename="sample-image.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"event[image]\"; filename=\"sample-image.jpg\"\r\nContent-Type: image/jpeg\r\n">}, "commit"=>"Update Event"}
Completed 500 Internal Server Error in 61ms (ActiveRecord: 0.0ms)
NoMethodError (undefined method `upload' for nil:NilClass):
app/controllers/events_controller.rb:4:in `create'
::1 - - [23/Aug/2018:10:02:25 MDT] "POST /events HTTP/1.1" 500 138644
http://localhost:3000/ -> /events
You should add this line of code to your Gemfile:
gem 'aws-sdk-s3', require: false
Then add this other to your environments/production:
config.active_storage.service = :amazon # or wharever storage you are using...

Paperclip not saving image, only creadted_at and updated_at getting stored and everything else is nil?

I am developing an rails api only app. I have integrated paper-clip but upon saving with POSTMAN and CURL both I get response as success, the record gets created but only created_at & updated_at fields get saved everything else remains nil.
If I create the record on console everything works fine.
Model
class Picture < ActiveRecord::Base
attr_accessor :image, :image_attributes
has_attached_file :image, :styles => {:medium =>"300x300"}
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
end
Controller
class PicturesController < ApplicationController
def new
picture = Picture.new
end
def create
print 'dir is'
puts Dir.pwd
result = { status: "failed" }
begin
picture = Picture.new
if picture.valid? && picture.save
result[:status] = "success"
end
rescue Exception => e
Rails.logger.error "#{e.message}"
end
render json: result.to_json
ensure
clean_tempfile
end
def picture_params
params.require(:picture).permit(:title,:image)
end
def parse_image_data(image_data)
#tempfile = Tempfile.new('item_image')
#tempfile.binmode
#tempfile.write Base64.decode64(image_data[:content])
#tempfile.rewind
uploaded_file = ActionDispatch::Http::UploadedFile.new(
tempfile: #tempfile,
filename: image_data[:filename]
)
uploaded_file.content_type = image_data[:content_type]
uploaded_file
end
def clean_tempfile
if #tempfile
#tempfile.close
#tempfile.unlink
end
end
end
My server log trace.
Started POST "/pictures?title=new" for ::1 at 2016-01-13 22:26:04 +0530
Processing by PicturesController#create as */*
Parameters: {"image"=>#<ActionDispatch::Http::UploadedFile:0x00000004924b50 #tempfile=#<Tempfile:/tmp/RackMultipart20160113-3226-brqash.png>, #original_filename="philosphy.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"image\"; filename=\"philosphy.png\"\r\nContent-Type: image/png\r\n">, "title"=>"new"}
dir is/home/anjan/Development/frankly_speak
(0.2ms) BEGIN
SQL (0.2ms) INSERT INTO `pictures` (`created_at`, `updated_at`) VALUES ('2016-01-13 16:56:04', '2016-01-13 16:56:04')
(38.2ms) COMMIT
Completed 200 OK in 75ms (Views: 0.1ms | ActiveRecord: 40.0ms)
You need to change
picture = Picture.new
to
picture = Picture.new(picture_params)
in create action

Rails file download not working in JSON API with devise token authentication

After ruining one working day, I am desperate for help.
I have a Rails 4.1.0 application which also exposes a JSON API. In the API I am using devise with token_authentication. There is an Image model with paperclip attachment. While trying to download the image, the postman plugin shows success with status 200. But the image isn't downloaded.
I have tried using both the send_file and send_data method. For both the server shows two log entries. While debugging also, I can see that the 'authenticate_user_from_token' method of ApiController gets executed twice and in the second time the 'X-Auth-Token header' is missing(which is obvious because I am not sending this second request). This results in a 401 Unauthorized error and the file isn't downloaded(See logs at the bottom). I am not sure why send_file or send_data method is causing a second request to server.
Here is my code.
controllers/api/v1/images_controller.rb
class Api::V1::ImagesController < Api::V1::ApiController
def download
#image = Image.find(params[:id])
# Tried send_file
send_file #image.pic.path(:original)
# Tried send_data
data = File.read(#image.pic.path(:original))
send_data data, filename: #image.pic.original_filename, type: #image.pic.content_type
end
end
controllers/api/v1/api_controller.rb
class Api::V1::ApiController < ApplicationController
respond_to :json
before_filter :authenticate_user_from_token!
before_filter :authenticate_user!
protect_from_forgery with: :null_session
private
def authenticate_user_from_token!
user_email = params[:email].presence
user = user_email && User.find_by_email(user_email)
auth_token = request.headers["X-Auth-Token"]
if user && Devise.secure_compare(user.authentication_token, auth_token)
sign_in user, store: false
end
end
end
controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
end
models/image.rb
class Image < ActiveRecord::Base
PAPERCLIP_ROOT = "#{Rails.root}/storage"
has_attached_file :pic, :styles => {:original => "720x720", :medium => "120x120", :thumbnail => "40x40"}
end
config/routes.rb
Rails.application.routes.draw do
#API
namespace :api , defaults: {format: :json} do
namespace :v1 do
resources :images do
member do
get 'download'
end
end
devise_scope :user do
post "/sign_in", :to => 'sessions#create'
post "/sign_out", :to => 'sessions#destroy'
end
end
end
end
server_log
Started GET "/api/v1/images/14/download?email=user#example.com" for 127.0.0.1 at 2014-09-21 13:57:25 +0530
ActiveRecord::SchemaMigration Load (0.7ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by Api::V1::ImagesController#download as */*
Parameters: {"email"=>"user#example.com", "id"=>"14", "image"=>{}}
.
.
Sent file /Users/rajveershekhawat/workspace/dine_connect/storage/images/pics/000/000/014/original/images.jpg (0.5ms)
Completed 200 OK in 14067ms (ActiveRecord: 13.5ms)
Started GET "/api/v1/images/14/download?email=user#example.com" for 127.0.0.1 at 2014-09-21 13:57:40 +0530
Processing by Api::V1::ImagesController#download as HTML
Parameters: {"email"=>"user#example.com", "id"=>"14"}
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."email" = 'user#example.com' LIMIT 1
Completed 401 Unauthorized in 3462ms
Please help. Thanks a lot.
Update:
Can somebody tell me why there are two request logs?
Can we even download, an image over json api whithout using Base64 encoding, like a normal download?
Try using send_data instead of send_file?
You might have to do a read on the paperclip file path.

Can't permit nested param in Rails 4

I've been ripping my hair off with this one. I have read all the doc about Rails 4 integrating strong params and that now everything has to be explicitly whitelisted. But it still won't go through!!!
Here is my setup
Models
class Course < ActiveRecord::Base
has_many :chapters
accepts_nested_attributes_for :chapters
end
class Chapter < ActiveRecord::Base
belongs_to :course
end
Controller
class CoursesController < ApplicationController
respond_to :json
def create
#course = Course.create permitted_params
respond_with #course
end
private
def permitted_params
params.require(:course).permit(:name, chapters_attributes: [:title, :content])
end
end
JSON from client
{
"course": {
"chapters": [{
"title": "qwerty",
"content": "foobar"
}],
"name": "Test course"
}
}
Server log
Started POST "/json/courses" for 10.0.2.2 at 2014-02-24 15:29:44 +0000
Processing by CoursesController#create as JSON
Parameters: {"course"=>{"chapters"=>[{"title"=>"qwerty", "content"=>"foobar"}], "name"=>"Test course"}}
Unpermitted parameters: chapters
Completed 201 Created in 96ms (Views: 52.1ms | ActiveRecord: 4.1ms)
Unpermitted params: chapters. I've been staring at this for hours with no avail. I honestly don't know what I'm doing wrong. Please tell me its right there and I just forgot some stupid magical param so I can move on.
I believe you just need to change to 'chapters' in your permitted_params method :
def permitted_params
params.require(:course).permit(:name, chapters: [:title, :content])
end
instead of "chapters_attributes"
I believe the issue is not in the controller or model, but in the JSON sent in the request.
Processing by CoursesController#create as JSON
Parameters: {"course"=>{"chapters"=>[{"title"=>"qwerty", "content"=>"foobar"}], "name"=>"Test course"}}
should instead be
Processing by CoursesController#create as JSON
Parameters: {"course"=>{"chapters_attributes"=>[{"title"=>"qwerty", "content"=>"foobar"}], "name"=>"Test course"}}
If you post your view code we can probably track down the issue fairly quickly.

Paperclip gem with Rails 4 doesn't save non-file fields

I'm building a Rails 4 app with the paperclip gem in which users can upload a video file from a form with several other fields (uploader_first_name, uploader_last_name, uploader_email).
The paperclip installation went smoothly (although I needed to add gem 'protected_attributes'
) and I'm able to save file to the correct and create the corresponding records in the videos table, however all the non-paperclip fields are null and I'm not sure why.
class Video < ActiveRecord::Base
belongs_to :project
attr_accessible :file
has_attached_file :file, :url=>"/tmp/video_uploads", :path=>":rails_root/tmp/video_uploads"
end
class VideosController < ApplicationController
def save
#video = Video.create(params[:video])
if #video.save
redirect_to root_path
else
redirect_to "somewhere_else"
end
end
#I tried with this too...
#private
#def video_params
#params.require(:video).permit( :uploader_first_name, :uploader_last_name, :uploader_email)
#end
end
In the view...
<h2>Upload your video</h2>
<% myclass = {:class=>'form-control'} %>
<%= form_for(:video, :url => {:action=>'save', :controller=>'videos'}, :html=>{:class=>'upload-form-js', :multipart=> true} ) do |f| %>
<div class="form-group">
<%= f.label(:uploader_first_name, "First Name") %>
<%= f.text_field(:uploader_first_name, myclass) %>
</div>
<div class="form-group">
<%= f.label(:uploader_last_name, "Last Name") %>
<%= f.text_field(:uploader_last_name, myclass) %>
</div>
<div class="form-group">
<%= f.label(:uploader_email, "Email") %>
<%= f.text_field(:uploader_email, myclass) %>
</div>
<div class="form-group">
<label>Video File</label>
<input type="file" name="video[file]" id="video_file"/></span>
</div>
<%= f.submit('Upload', {class: 'btn btn-primary btn-block'}) %>
<% end %>
Update 1
I changed to this...
class VideosController < ApplicationController
def save
#video = Video.create( video_params )
if #video.save
redirect_to root_path
else
redirect_to "somewhere_else"
end
end
private
def video_params
params.require(:video).permit(:file, :uploader_first_name, :uploader_last_name, :uploader_email)
end
end
...and now I get this error:
Errno::EISDIR in VideosController#save
Is a directory - /Applications/MAMP/htdocs/clippo2/tmp/video_uploads
Don't I want the url/path to point to a directory?
Update 2
I changed the video model to...
has_attached_file :file, :url=>"/tmp/video_uploads/:basename.:extension", :path=>":rails_root/tmp/video_uploads/:basename.:extension"
...and now no errors, files get saved to the right directory and the corresponding fields added to the new row, but all other fields are still NULL (original problem).
Update 3
I turned on the debugger and here's what I see after I try to upload a file. It looks like a strong parameters error but I'm not sure how to fix it:
Started POST "/videos/save" for 127.0.0.1 at 2013-08-27 09:21:34 -0400
Processing by VideosController#save as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"es4wPqFr9xPBUFsbHQR/gAzofDC+ZwYsiiJ7RAQZUHk=", "video"=>{"uploader_first_name"=>"adsfasdf", "uploader_last_name"=>"asdfasdf", "uploader_email"=>"asdfasdf", "file"=>#<ActionDispatch::Http::UploadedFile:0x007fc4782e31e8 #tempfile=#<Tempfile:/var/folders/f2/jhv7xx0j3hlckhcg_jbv6hr00000gn/T/RackMultipart20130827-89636-188f0hs>, #original_filename="sample_iPod.m4v", #content_type="video/mp4", #headers="Content-Disposition: form-data; name=\"video[file]\"; filename=\"sample_iPod.m4v\"\r\nContent-Type: video/mp4\r\n">, "project_hashed_id"=>"1377539908"}, "commit"=>"Upload"}
{"utf8"=>"✓", "authenticity_token"=>"es4wPqFr9xPBUFsbHQR/gAzofDC+ZwYsiiJ7RAQZUHk=", "video"=>{"uploader_first_name"=>"adsfasdf", "uploader_last_name"=>"asdfasdf", "uploader_email"=>"asdfasdf", "file"=>#<ActionDispatch::Http::UploadedFile:0x007fc4782e31e8 #tempfile=#<Tempfile:/var/folders/f2/jhv7xx0j3hlckhcg_jbv6hr00000gn/T/RackMultipart20130827-89636-188f0hs>, #original_filename="sample_iPod.m4v", #content_type="video/mp4", #headers="Content-Disposition: form-data; name=\"video[file]\"; filename=\"sample_iPod.m4v\"\r\nContent-Type: video/mp4\r\n">, "project_hashed_id"=>"1377539908"}, "commit"=>"Upload", "controller"=>"videos", "action"=>"save"}
Unpermitted parameters: project_hashed_id
WARNING: Can't mass-assign protected attributes for Video: uploader_first_name, uploader_last_name, uploader_email
app/controllers/videos_controller.rb:6:in `save'
[1m[35m (0.2ms)[0m BEGIN
[1m[36mSQL (0.3ms)[0m [1mINSERT INTO `videos` (`created_at`, `file_content_type`, `file_file_name`, `file_file_size`, `file_updated_at`, `updated_at`) VALUES ('2013-08-27 13:21:34', 'video/mp4', 'sample_iPod.m4v', 2236480, '2013-08-27 13:21:34', '2013-08-27 13:21:34')[0m
[1m[35m (9.0ms)[0m COMMIT
Redirected to http://localhost:3000/
Completed 302 Found in 21ms (ActiveRecord: 9.5ms)
Welcome to the rails 4. 'attr_accessible' was replaced by the strong parameters.
http://api.rubyonrails.org/classes/ActionController/StrongParameters.html
Upd. Can you try this?
def create
#video = Video.create(video_params)
end
private
def video_params
params.require(:video).permit(:file, :uploader_first_name, :uploader_last_name, :uploader_email)
end
I figured out what's going on. The strong parameters were getting in the way because I'm using attr_accessible in the model. Instead of fiddling with the require() and permit() I removed them entirely and added the missing fields to the attr_accessible and now it works:
class Video < ActiveRecord::Base
belongs_to :project
attr_accessible :file, :uploader_first_name, :uploader_last_name, :project_hashed_id, :uploader_email, :rating
has_attached_file :file, :url=>"/tmp/video_uploads/:basename.:extension", :path=>":rails_root/tmp/video_uploads/:basename.:extension"
end
class VideosController < ApplicationController
def save
logger.debug( params )
##video = Video.new( video_params )
#video = Video.new( params[:video])
if #video.save
redirect_to root_path
else
redirect_to "somewhere_else"
end
end
end
I realize that attr_accessible was replaced by strong parameters in Rails 4 but I couldn't get paperclip to work without it. If anyone can tell me how, I'd love to know.
Update
I removed attr_accessible entirely and just used the strong parameters...
class VideosController < ApplicationController
def save
logger.debug( params )
#video = Video.new( video_params )
if #video.save
redirect_to root_path
else
redirect_to "somewhere_else"
end
end
private
def video_params
#params.require(:video).permit(:file, :uploader_first_name, :uploader_last_name, :uploader_email, :project_hashed_id)
params.require(:video).permit!
end
end
...and it works BUT you have to remember to remove the protected_attributes gem and restart rails s for it to take effect (this n00b mistake cost me 45 minutes!)
Moral of this story: Don't mix and match attr_accessible with strong params. Do one or the other and paperclip will work with strong parameters.

Resources