Handy File Processing / Rails - ruby-on-rails

I'm searching for quite some time now a handy Method or even better, a Gem, that would allow me to CRUD Files.
Specific needs are:
Create a file from a :text string. (and control file type. e.g. test.js)
Edit the File (Rewrite) if an update has occurred to :text
Basically the whole CRUD Powerhouse.
Now, of course i know that there is no Magic Willie that will do this all by himself, i'm just looking for a right direction, from where i can start.
Use Case:
We have a documents controller with the variables:
:title
:body
:user_id
The :body (a simple text_area input) contains some .js code. How can i create a file (e.g test.js) based on :body which was entered by the User.
E.g. for simply creating the file => File.open('text.js', 'w') { |file| file.write(#something.body) }
So far i'm here
def create
#script = current_user.scripts.build(script_params)
# Creating Folder (if it doesn't exist already)
directory_name = "#{Rails.root}/public/userscripts/#{#script.user_id}"
Dir.mkdir(directory_name) unless File.exists?(directory_name)
# Write the file with model attribute :source
File.open("public/userscripts/#{#script.user_id}/#{#script.name}.user.js", 'w') { |file| file.write(#script.source) }
end

Paperclip will allow you to attach files and you can update them as well.
You can create a temporary file, assign it to the attachment attribute, then save the model.
# create and write a file with the contents you want
open "/tmp/tmpfile" do |f|
model.attachment = f
model.save!
end
You can put this in a before_save filter to always update the file attachment.
class Model < ActiveRecord::Base
has_attached_file attachment
before_save :update_attachment
def update_attachment
File.open("/tmp/tmpfile", 'w') { |file| file.write(self.body) }
open "/tmp/tmpfile" do |f|
self.attachment = f
self.attachment_content_type = "text/javascript"
end
end

Related

Uploader produces errors regarding the column in which it should store the path

An Image model has a 1:1 association with an Organization model. In the organizations controller, the create method calls on an Image model method called upload_file.
def create
#organization = Organization.new(new_params)
if #organization.save
Image.upload_file(#organization.id)
end
end
The upload_file method uses a carrierwave uploader to store a standard file in an Amazon S3 bucket. To this end, the Image model includes mount_uploader :file_name, ImageUploader.
My question is how to create an Image instance for the uploaded file? The path to the stored file should be stored in the column file_name in the Image model. And the organization associated with the image should be stored in the column organization_id in the Image model. How can I do this? More specifically, what code should I add for this to the model method below? (also see the comments in the method below.
def self.upload_file(organization_id)
file = 'app/assets/emptyfile.xml'
uploader = ImageUploader.new
uploader.store!(file)
# Am I correct to assume that the previous line uploads the file using the uploader, but does not yet create an Image record?
# If so, then perhaps the next line should be as follows?:
# Image.create!(organization_id: organization_id, filename: file.public_url)
# I made up "file.public_url". What would be the correct code to include the path that the uploader stored the image at (in my case an Amazon S3 bucket)?
end
Currently in rails console I get the following error:
>> uploader = ImageUploader.new
=> #<ImageUploader:0x00000005d24f88 #model=nil, #mounted_as=nil, #fog_directory=nil>
>> file = 'app/assets/emptyfile.xml'
=> "app/assets/emptyfile.xml"
>> uploader.store!(file)
CarrierWave::FormNotMultipart: CarrierWave::FormNotMultipart
from /usr/local/rvm/gems/ruby-2.2.1/gems/carrierwave-0.10.0/lib/carrierwave/uploader/cache.rb:120:in `cache!'
etc.
You don't have to call the uploader yourself. Carrierwave comes with a mechanism to do the uploading and storing in AR models for you:
class Organization < ActiveRecord::Base
mount_uploader :image, ImageUploader
end
Then you can do
u = Organization.new
u.image = params[:file] # Assign a file like this, or
# like this
File.open('somewhere') do |f|
u.image = f
end
u.save!
u.image.url # => '/url/to/file.png'
u.image.current_path # => 'path/to/file.png'
u.image # => 'file.png'
Please visit the carrierwave README for more extensive examples.

Store uploaded files carrierwave RoR

i am trying to upload a file with carrierwave in my rails app and currently this is my code:
Controller:
def fileSave
#code.store!(code)
end
View:
= form_for #code = Code.new(params[:code]), :as => :code, :html => {:multipart => true} do |f|
div class="browse"
span
= f.file_field :code
= f.submit 'Upload'
Uploader:
# encoding: utf-8
class CodeUploader < CarrierWave::Uploader::Base
def pre_limit file
#require 'debugger'; debugger
if file && file.size > 100.megabytes
raise Exception.new('too large')
end
true
end
storage :file
def store_dir
"public/uploads"
end
def extension_white_list
%w(txt js ttf html)
end
def filename
"file.txt" if original_filename
end
end
Model:
require 'carrierwave/orm/activerecord'
class Code < ActiveRecord::Base
attr_accessor :code
mount_uploader :code, CodeUploader
end
And my problem is i can not store the uploaded file. x[ I am sure this is like 3 lines of code but i can not figure it out. Also the file to be uploaded is expected to be txt (probably figured that out looking the extension list).
Thanks to all readers and answerers. :}
P.S. I was wondering if i could create some kind of imaginary file, a file which is not really created. The is idea is if a take a text from a textarea and create a file (the imaginary one), store the text inside and then eventually save the whole file (maybe use carrierwave as and manually store it).

Direct upload with Cloudinary and Carrierwave

I've been following the instructions provided by Cloudinary, but have not been able to get direct uploading working. To further complicate things my image upload is a polymorphic class and is usually in a nested form.
I'm using both the Cloudinary and Carrierwave gems. In the non-direct setup everything works properly however unicorn times out if there are too many images being uploaded at once (which may frequently be the case)
Below is the partial that adds a file upload. It is nested in multiple different forms and the user can add and remove fields dynamically. Per the instructions, I tried to replace = f.file_field :asset and = f.hidden_field :asset_cache with = cl_image_upload :asset, however, this throws an error of: wrong number of arguments (1 for 2..3). When adding a second parameter it is appended to data-cloudinary-field in the generated HTML. Additionally no upload takes place when an image is added and no reference is attached to the record.
_image_fields.html.haml
.image-field-group
.field
= f.label :asset, "Image"
= cl_image_upload :asset
/ = f.file_field :asset
/ = f.hidden_field :asset_cache
- if f.object && f.object.asset && f.object.asset.filename
.image-box
= cl_image_tag(f.object.asset.filename.to_s, :transformation => 'hint', alt: f.object.asset.filename.to_s)
.remove-fields
= link_to_remove_fields f
Here are the associated files:
image.rb
class Image < ActiveRecord::Base
default_scope order('images.id ASC')
attr_accessible :asset,
:asset_cache
belongs_to :imageable, polymorphic: true
mount_uploader :asset, ImageUploader
end
image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
include Cloudinary::CarrierWave
def extension_white_list
%w(jpg jpeg gif png)
end
end
EDIT: Added Images Controller
images_controller.rb
class ImagesController < ApplicationController
before_filter :load_imageable
def index
#images = #imageable.images
end
def new
#image = #imageable.images.new
end
def create
#image = #imageable.images.new(params[:image])
if #image.save
redirect_to #imageable, notice: "Image created."
else
render :new
end
end
private
def load_imageable
resource, id = request.path.split('/')[1, 2]
#imageable = resource.singularize.classify.constantize.find(id)
end
end
The following documentation section describes how to use direct image uploading from the browser in your Ruby on Rails application. Make sure to include jQuery and the required plugins in the correct order and to add the required Javascript configuration.
http://cloudinary.com/documentation/rails_image_upload#direct_uploading_from_the_browser
Embedding a file input field that performs direct image uploading is done using the cl_image_upload_tag helper method that accepts the name of the input field.
When using CarrierWave, you can use the cl_image_upload helper method. When calling this method directly, you need to pass the object name and the attribute them (as you do with other Rails view helper methods such as text_field_tag and text_field). Alternatively, you can use it with Rails' standard form builders.
Assuming your model is called entity and your attribute with a mounted CarrierWaver uploader is called asset, the following view code should embed a signed file input field for direct uploading from the browser:
= form_for(:entity) do |f|
= f.cl_image_upload(:asset)
In addition, as you can see below you can use present? to check if the asset exists and pass the CarrierWave attribute directly to cl_image_tag. Alternatively, you can use CarrierWave standard versions instead of dynamically building image URLs using cl_image_tag.
- if f.object && f.object.asset.present?
.image-box
= cl_image_tag(f.object.asset, :transformation => 'hint', alt: f.object.asset.filename.to_s)
If the file input field was added successfully to your view but no direct uploading is performed, you should verify that there are no Javascript errors in the console and that all jQuery plugins were included correctly.

Paperclip save attachment

Is there a better way to save some string as an attachment via Paperlip as making a tmp file, putting the string into it, opening it again and saving it as an attachment ?
Like this :
def save_string data
tmp_file = "/some/path"
File.open(tmp_file,'w') do |f|
f.write(data)
end
File.open(tmp_file,'r') do |f|
ceneo_xml = f
save!
end
end
There is actually a better way - you can wrap it to StringIO which Paperclip enhances and you will get a pseudo uploaded file in no time. You can customize it by defining instance methods or directly create a subclass of StringIO like this
class InvoiceAttachment < StringIO
def initialize(invoice, content)
#invoice = invoice
super(content)
end
def original_filename
from = #invoice.from
to = #invoice.to
date = #invoice.created_at.strftime('%B-%Y').downcase
"invoice_#{date}_from_#{from}_to_#{to}.pdf"
end
def content_type
'application/pdf'
end
end
Enjoy!
Paperclip stores files alongside your models -- this is what it has been written to do, so I think the short answer is "no".
If you look in attachment.rb in the Paperclip source you'll see a method called def assign uploaded_file. If you look at the implementation of this method you can see that it expects the uploaded file object to have a certain methods defined on it.
You could create your own class which followed the same interface as Paperclip expects, but to be honest your solution of saving a file and assigning that to Paperclip is probably the easiest approach.

Rails: Saving the contents of a binary field to a file

I have a model with a binary field that contains a file. I'd like to save this file to disk as part of a process I need to do. For some reason, I can't find anything on how to do this.
The model contains a filename field and a file_contents field. I'd like to do something like this:
model = SomeModel.find :first
model.file_contents.save_to_file(model.filename)
Any help would be appreciated!
I don't know why you'd want to call #save_to_file on the file contents instead of the model. Since you defined file_contents as an AR attribute I guess you want to save it to the DB and save it to disk. If that's the case you can simply add a method like this to your model:
class YourModel < ActiveRecord::Base
# ... your stuff ...
def save_to_file
File.open(filename, "w") do |f|
f.write(file_contents)
end
end
end
And then you'd simply do:
obj = YourModel.find(:first)
obj.save_to_file
In ActiveRecord, the :binary type that you use to define your column type in your migration is going to map to a blob type in the database. So that wouldn't allow you to save to a file.
I think you would need to define a model class that is not a subclass of ActiveRecord::Base and define a custom save_to_file method for that class using the file i/o support in Ruby (the IO class and its subclass, File).
class SomeModel
attr_accessor :file
attr_accessor :contents
def initialize
#file = File.new("file.xyz", "w")
end
def save_and_close
#file << contents
#file.close
end
end

Resources