Can't read an uploaded file with Ruby's Framework Padrino - ruby

I have this form for uploading files:
-# coding: utf-8
- content_for(:body_classes, "body3")
.content
- form_tag url(:images, :create), :method => :post, :multipart => true do
= file_field_tag :file
= submit_tag "Upload"
And this Controller to handle it:
Fbapp.controllers :images do
get :new do
render 'images/new'
end
post :create do
require 'net/ftp'
file = params[:file]
ftp = Net::FTP.new('xxx.xxx.xxx.xxx')
ftp.passive = true
ftp.login('user','pass')
ftp.storbinary("STOR " + "original_filename", StringIO.new(file.read), Net::FTP::DEFAULT_BLOCKSIZE)
ftp.quit
end
end
And every time I try to upload a file I get "Internal Server Error". And my log has this:
NoMethodError - undefined method `read' for #<Hash:0x00000003697780>:
I'm trying this on Heroku by the way. I can't figure out what's the problem... It seems to work for a lot of people but me.

You should use:
file = params[:file][:tempfile]
and I suggest to retrieve the filename
name = params[:file][:filename]

Related

Mongo object's id as dirname for file upload in Sinatra/Mongoid

I'm working on Sinatra site which allows user to upload files. I got this action route:
post '/upload' do
params.delete 'submit'
UsrUpld.new(
:name => params[:name]
:created_at => Time.now
).save
params[:photos].each do |photo|
File.open('public/uploads/' + UsrUpld.id + '/' + photo[:filename], 'w') do |file|
file.write(photo[:tempfile].read)
end
end
redirect '/index'
end
I think this should create document in MongoDB with two fields name and created_at, the take file from POST request and write it in public/uploads/ID/FILE.jpg. But Pow returns me undefined method `id' for UsrUpld:Class. How to ask object's id in route with Mongoid?
Thank you in advance.
To ask an id, object should placed in variable which should contain exactly this object, so code should look like this:
post '/upload' do
params.delete 'submit'
u = UsrUpld.new(
:name => params[:name],
:created_at => Time.now
)
u.save
params[:photos].each do |photo|
unless File.exists?('public/media/' + u.id)
Dir.mkdir('public/media/' + u.id)
end
File.open('public/uploads/' + u.id + '/' + photo[:filename], 'w') do |file|
file.write(photo[:tempfile].read)
end
end
redirect '/index'
end
Also dir should exist before opening the file, thats why Dir.mkdir line added.

Manually upload and save files in Carrierwave

I have a directory of existing files which I need to migrate into my rails app as part of a legacy migration. Essentially I need to upload these files manually and save a new record for them in the database. I haven't quite found the proper way to do this. Currently I have the following in a rake task:
#attachments.each do |attachment|
begin
new_attachment = Attachment.new
#attachment_file_path = "/home/username/Attachments/" + attachment.Filename
file = File.open(#attachment_file_path)
new_attachment[:file] = new_attachment.file.store!(file)
# Map old record fields to new
new_attachment.attributes = {
:project_id => attachment.ProjectID,
:name => attachment.Description,
:user_id => attachment.UserId,
:created_at => attachment.CreatedDate,
:updated_at => attachment.LastModifiedDate
}
new_attachment.save!
puts "Attachment added successfully "
rescue => error
puts "Error migrating Attachment: #{error}"
end
end
attachment.rb
class Attachment < ActiveRecord::Base
mount_uploader :file, FileUploader
end
uploader:
class FileUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
include CarrierWave::MimeTypes
process :set_content_type
storage :fog
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_white_list
%w(jpg jpeg gif png pdf doc docx txt)
end
version :thumb do
process resize_to_fit: [152, nil]
end
def default_url
ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
end
protected
def image?(new_file)
if new_file.content_type == nil
return false
else
new_file.content_type.include? 'image'
end
end
end
This does not work currently. The file never gets uploaded, and occasionally I get the following error:
Failed to manipulate with rmagick, maybe it is not an image? Original Error: no decode delegate for this image format
In this instance, the file is a '.doc' file.
What is the correct way to open a local file and upload it manually via Carrierwave?
Any help is appreciated.
Try this
#attachments.each do |attachment|
begin
options = {
:project_id => attachment.ProjectID,
:name => attachment.Description,
:user_id => attachment.UserId,
:created_at => attachment.CreatedDate,
:updated_at => attachment.LastModifiedDate,
:file => File.new(File.join("/home/username/Attachments/",attachment.Filename))
}
new_attachment = Attachment.new(options)
new_attachment.save!
puts "Attachment added successfully "
rescue => error
puts "Error migrating Attachment: #{error}"
end
end
Perhaps that would do for you as carrierwave would internally call store! for you
Question?
Failed to manipulate with rmagick, maybe it is not an image? Original Error: no decode delegate for this image format
Not sure what are you trying to over here because you have define an image? method which is not specified in condition also is that something that you want the content_type to be only present for image file
if no perhaps only the process call would work
process :set_content_type
if yes then perhaps you have to do something like this
process :set_content_type , :if => :image?
def image?(new_file)
%w(jpg jpeg gif).include?(new_file.extension)
end
Hope this help
EDIT based upon the comment
try this just used the condition same logic
version :thumb ,:if => image? do
// your code
end

Ruby JSON issue

I know the title is a bit vague, but I dont know what to put on there.
I'm developing an API with Sinatra for our backend in Ruby. The thing is that I need to be able to pass JSON to the service representing a User. The problem I'm facing is that when I run my tests it does not work, but doing it manually against the service it does work. I'm guessing there is an issue with the JSON format.
I've updated my User model to rely on the helpers from ActiveModel for the JSON serialization. I was running in too much problems with manual conversions. This is what the base User model looks like:
class User
include ActiveModel::Serializers::JSON
attr_accessor :login, :email, :birthday, :created_at, :updated_at, :password_sha, :password_salt
# Creates a new instance of the class using the information stored
# in the hash. If data is missing then nill will be assigned to the
# corresponding property.
def initialize(params = {})
return if params.nil?
self.login = params[:login] if params.key?("login")
self.email = params[:email] if params.key?("email")
self.birthday = Time.parse(params[:birthday]) rescue Time.now
if params.key?("password_salt") && params.key?("password_sha")
self.password_salt = params["password_salt"]
self.password_sha = params["password_sha"]
elsif params.key?("password")
self.set_password(params[:password])
end
self.created_at = Time.now
end
def attributes
{:login => self.login, :email => self.email, :birthday => self.birthday, :created_at => self.created_at, :updated_at => self.updated_at, :password_sha => self.password_sha, :password_salt => self.password_salt}
end
def attributes=(params = {})
self.login = params['login']
self.email = params['email']
self.birthday = params['birthday']
self.created_at = params['created_at']
self.updated_at = params['updated_at']
self.password_sha = params['password_sha']
self.password_salt = params['password_salt']
end
end
I'm using Cucumber, Rack::Test and Capybara to test my API implementation.
The code of the API application looks like this:
# This action will respond to POST request on the /users URI,
# and is responsible for creating a User in the various systems.
post '/users' do
begin
user = User.new.from_json(request.body.read)
201
rescue
400
end
end
In the above piece I expect the json representation in the request body. For some reason the params hash is empty here, don't know why
The test section that makes the actuall post looks like this:
When /^I send a POST request to "([^\"]*)" with the following:$/ do |path, body|
post path, User.new(body.hashes.first).to_json, "CONTENT_TYPE" => "application/json"
end
The example output JSON string generated by the User.rb file looks like this:
"{"user":{"birthday":"1985-02-14T00:00:00+01:00","created_at":"2012-03-23T12:54:11+01:00","email":"arne.de.herdt#gmail.com","login":"airslash","password_salt":"x9fOmBOt","password_sha":"2d3afc55aee8d97cc63b3d4c985040d35147a4a1d312e6450ebee05edcb8e037","updated_at":null}}"
The output is copied from the Rubymine IDE, but when I submit this to the application, I cannot parse it because:
The params hash is empty when using the tests
doing it manually gives me the error about needing at least 2 octets.

How to upload a file temporarily in Rails 3?

I'm creating CSV-upload functionality for a site of mine.
I'm looking to upload a file, parse it, and then dispose of it.
I know I can upload and save a file using Paperclip, but that seems a bit like overkill.
All I need to do is parse the uploaded file and never save it.
How would I go about doing this in Rails 3?
Note: I'd prefer to do the uploading manually without using an external gem so I can learn how to process works, but any suggestions are welcome.
Thanks!
Use the file_field helper in your form, then in your controller you can use File.Write and File.read to save the file.
E.g. View
<%= form_for #ticket do |f| %>
<%= f.file_field :uploaded_file %>
<% end %>
Controller
def upload
uploaded = params[:ticket][:uploaded_file]
File.open(<insert_filename_here>, 'w') do |file|
file.write(uploaded.read)
end
end
Edit: Just saw #klochner's comment, that link says pretty much what I have said so follow that: RubyOnRails Guides: Uploading Files.
Paste this in your model
def parse_file
File.open(uploaded/file/path, 'w') do |f| # Feed path that user gives in some way
## Parse here
end
end
this in view
<%=form_for #page, :multipart => true do |f|%>
<ul><li><%= f.label :file%></li>
<li><%= f.file_field :uploaded_file%></li></ul>
<%end%>
Let me know if this works. If it fails figure out a way to feed path of uploaded_file in parse_file method (the definite way which will work is storing file location in db and picking up from there, but it is not the right way to do this thing). Otherwise, I guess it should work.
Complete Example
Take, for example, uploading an import file containing contacts. You don't need to store this import file, just process it and discard it.
Routes
routes.rb
resources :contacts do
collection do
get 'import/new', to: :new_import # import_new_contacts_path
post :import, on: :collection # import_contacts_path
end
end
Form
views/contacts/new_import.html.erb
<%= form_for #contacts, url: import_contacts_path, html: { multipart: true } do |f| %>
<%= f.file_field :import_file %>
<% end %>
Controller
controllers/contacts_controller.rb
def new_import
end
def import
begin
Contact.import( params[:contacts][:import_file] )
flash[:success] = "<strong>Contacts Imported!</strong>"
redirect_to contacts_path
rescue => exception
flash[:error] = "There was a problem importing that contacts file.<br>
<strong>#{exception.message}</strong><br>"
redirect_to import_new_contacts_path
end
end
Contact Model
models/contact.rb
def import import_file
File.foreach( import_file.path ).with_index do |line, index|
# Process each line.
# For any errors just raise an error with a message like this:
# raise "There is a duplicate in row #{index + 1}."
# And your controller will redirect the user and show a flash message.
end
end

Rails 3 - custom ajax action is not working

I want to create a custom action in Rails which will update views and print some info on div.
I use that gem for file upload:
https://github.com/valums/file-uploader/blob/master/client/fileuploader.js
After successful upload I want to update with ajax page how many miliseconds it takes.
In old Rails I would write that with:
def set_tab
#diff = count_miliseconds_method
render :update do |page|
page.replace_html "place_menu", render( :partial => 'place_menu')
end
end
But I cant figure out how to do that in Rails 3.1.
My custom action controller code:
def custom
[...] # Here everything works OK
start_time = Time.now
Some_method
end_time = Time.now
#diff = ((end_time - start_time)*100).to_i # counted miliseconds
respond_to do |format|
format.json {render :json => {:success => true, :time => #diff}, :status => :created, :location => custom_words_path}
end
end
My custom.js.erb code
var el = $('#upload-log');
el.append("#{#diff} ms");
Unfortunately this doesnt work. I get response e.g.
{"success":true, "time":324}
but js.erb file doesnt get executed and page doesnt containt information about miliseconds.
Any idea how to fix that?
Update
Github repo:
https://github.com/there-is-no-spoon/Anagram
To execute js.erb file you have to pass
:format => :js
to your path generating method - for example:
link_to "My custom action", my_action_path(:format => :js)
You're returning JSON now (in Rails 3.1) not a chunk of string containing Javascript (as was the case before).
You need to write your code which handles your result where you make the Ajax Call. I assume you're using jQuery. So where you make the Ajax call, implement the success handler and do the
var el = $("#upload-log");
...
stuff there.
Basically server does not return Javascript anymore, it is completely on the client side only.
You need to implement the onComplete method of your file upload plugin. Read the manual of your js plugin, its mentioned clearly.

Resources