Access CarrierWave image url using SQL in Rails migration - sql

I'm working on a small app that uses CarrierWave for image uploading, but (for reasons that are a bit long and not really relevant) we have to stop using CarrierWave and start uploading images with our own custom requests to different cloud storage services.
But I still need to have the URLs to images that were already uploaded using CarrierWave, and I won't have access to the image_url method once I unmount the CarrierWave uploader, so I want to save all the urls to a new column on my model, and to have that migration be as optimized as possible.
I've searched for ways to access directly the url from the database (I mean, CarrierWave has to store that somewhere) but no luck so far.
I could do something like this (business_image is the column that the uploader is mounted on, image_url is the new column where I want to store the url):
def change
add_column :business_cards, :image_url, :string
BusinessCard.all.each do |bc|
bc.update(image_url: bc.business_image_url)
end
end
But that is obviously not optimized at all since it loads all business cards and updates them one by one. Is there a way to do it in a single SQL statement?
(I'm using Rails 5.1.4, PostgreSQL 10.3 and carrierWave 1.2.1)

One way would be too use batch function and update record in batches, you can use transaction so that if there are any errors the changes would be rolled back.
def change
add_column :business_cards, :image_url, :string
BusinessCard.find_each(batch_size: xxx) do |bc|
ActiveRecord::Base.transaction do
bc.update(image_url: bc.business_image_url)
rescue => e
raise ActiveRecord::Rollback
end
end
end
Hope it helps!!

Related

Duplicate mounted_uploader Carrierwave

So I have an model, Photo, I want to duplicate the whole model including the mounted image.
old_photo = Photo.find(id)
new_photo = Photo.new(old_photo.attributes)
class Photo
include Mongoid::Document
mount_uploader :image, ImageUploader
end
But how can I duplicate the mounted image and all it's versions? i.e create an exact copy of the photo, not use the same. (since they can be changed later)
This question is similar: https://stackoverflow.com/questions/7287905/duplicate-an-image-on-amazon-s3-that-was-uploaded-using-carrierwave-fog-and-rai
He's asking about AWS::S3::S3Object.copy from the aws-s3 gem, can this be used to achieve this? if so, how?
I'm using fog for the connection to S3, can it be done with fog? If so, how?
Update:
new_photo = Photo.new(old_photo.attributes)
new_photo.image.download!(old_photo.image_url)
new_photo.store_image!
raise new_photo
=> <#Photo _id: 4f1ff69566eaa70ed800001d, image: nil>
raise new_photo.image
=> https://x.s3.amazonaws.com/uploads/photo/image/4f1ff76566eaa70ed8000020/file.png
Any idea why image is nil on new_photo while I still can access it?

Export A Record To CSV

I have a Posts table in my Rails 3.0.10 app. I want to give my users the option to export a particular Post record to CSV format, not all of them. And while my Post table has a lot of fields, I only want to export the title and the body.
After doing some searching apparently the best way to do this is through FasterCSV. And apparently it's already built in Ruby 1.9.2, which I'm using. Thing is pretty much all the tutorials are outdated (from Rails 1 or 2) and I have absolutely no idea how to accomplish this.
I've tried putting in my posts_controller.rb
def export_to_csv
#post = Post.find(params[:id])
csv_string = CSV.generate do |csv|
csv << [#post.title, #post.body]
end
# send it to the browsah
send_data csv_string,
:type => 'text/csv; charset=iso-8859-1; header=present',
:disposition => "attachment; filename=post.csv"
end
Which I THINK may be the right code, but I have no idea how to use it in my view. Ideally I want to have a link to export the CSV file, but I'm thinking it has to be done through a form_tag?
Would appreciate if someone could point me towards the right direction. Thanks.
After several hours of Googling and experimentation I found the answer.
1.) Install this gem: https://github.com/dasil003/csv_builder
2.) Add respond_to do |format| format.csv to the action you want to turn into a CSV (in my case, the def show part of the posts_controller
3.) Create a action.csv.csvbuilder file (in my case, show.csv.csvbuilder) and add the data you need (in my case, add csv << [#post.title, #post.body])
4.) Add a link to the CSV in the views.

Paperclip not saving files with save()

I have a little problem with paperclip saving the data passed through the form...
If I'm trying to save the record with .save() it won't save.. When I look in the server/log there are no errors or warnings for the paperclip gem :-/
# trying to save the record with save() -- not working :-/
def create
#baan_import = BaanImport.new(params[:baan_import])
if #baan_import.save
redirect_to(baan_imports_url)
else
render 'new'
end
end
Server-log: (using .save() in controller)
https://gist.github.com/1327347
I just don't get it why it's working if I'm using .create instead of .save()
# trying to save the record with Model.create() -- working!
def create
#baan_import = BaanImport.create(params[:baan_import])
redirect_to(baan_imports_url)
end
Server-log: (using .create() in controller)
https://gist.github.com/1327359
Can some one explain me why it's working with create and not with save??
Thanks,
Michael
Can you show us the BaanImport model. My first guess is you're possibly missing baan_upload in attr_accessible on your model, and as a result, Rails will not let you mass assign the file parameter for upload.
Can you also confirm (would appear as though it's properly set up) that your form has html => {:multipart => true} as an option?

multiple image upload with dragonfly

i was trying for multiple image upload with dragonfly in rails3. i searched for some tutorials, but couldn't find any. i found a tutorial for multiple image upload with Carrierwave, but couldnt find luck with dragonfly .. any help please :)
Preface
Dragonfly itself can be used to manage media for your project in general, similar to paperclip. The question itself boils down to the multiple file upload within a rails application. The some tutorials on this topic available, which can easily be adapted to models using Dragonfly for storing specific files on them. I would suggest you look into those and try to adapt them for your project.
However, I can present a minimum example which i built for a rails 3.2 app currently in development, which isn't perfect (validation handling for example), but can give you some starting points.
Example
Just for reference, the essential idea is taken from here. This example is done with Rails 3.2.x.
Let's say you have a vacation database, where users may create trip reports on vacations they took. They may leave a small description, as well as some pictures.
Start out by building a simple ActiveRecord based model for the trips, lets just call it Trip for now:
class Trip < ActiveRecord::Base
has_many :trip_images
attr_accessible :description, :trip_images
end
As you can see, the model has trip images attached to it via a has_many association. Lets have a quick look at the TripImage model, which uses dragonfly for having the file stored in the content field:
class TripImage < ActiveRecord::Base
attr_accessible :content, :trip_id
belongs_to :trip_id
image_accessor :content
end
The trip image it self stores the file attachment. You may place any restrains within this model, e.g. file size or mime type.
Let's create a TripController which has a new and create action (you can generate this via scaffolding if you like, it is by far nothing fancy):
class TripController < ApplicationController
def new
#trip = Trip.new
end
def create
#trip = Trip.new(params[:template])
#create the images from the params
unless params[:images].nil?
params[:images].each do |image|
#trip.trip_images << TripImages.create(:content => image)
end
if #trip.save
[...]
end
end
Nothing special here, with the exception of creating the images from another entry than the params hash. this makes sense when looking at the the file upload field within the new.html.erb template file (or in the partial you use for the fields on the Trip model):
[...]
<%= f.file_field :trip_images, :name => 'images[]', :multiple => true %>
[...]
This should work for the moment, however, there are no limitations for the images on this right now. You can restrict the number of images on the server side via a custom validator on the Trip model:
class Trip < ActiveRecord::Base
has_many :trip_images
attr_accessible :description, :trip_images
validate :image_count_in_bounds, :on => :create
protected
def image_count_in_bounds
return if trip_images.blank?
errors.add("Only 10 images are allowed!") if trip_images.length > 10
end
end
I leave this up to you, but you could also use client side validations on the file field, the general idea would be to check the files upon changing the file field (in CoffeeScript):
jQuery ->
$('#file_field_id').change () ->
#disable the form
for file in this.files
#check each file
#enable the form
Summary
You can build a lot out of existing tutorials, as dragonfly does not behave that differently to other solutions when it comes to just to uploading files. However, if you'd like something fancier, I'd suggest jQuery Fileupload, as many others have before me.
Anyways, I hope I could provide some insight.

Rails 3.1 RC4 remove_attachment doesnt remove!

Using Carrierwave 0.5.4 on Rails 3.1 RC4.
In Rails console, I do:
#foo.attachment
returns:
=> http://cdn.site_name.com/uploads/users/2/banners/banner.png
However:
#foo.remove_attachment!
returns:
=> [:remove_versions!]
The record still remains in the DB, BUT the file is removed in the S3 bucket.
What is going on?
Ahhh, after further investigating. This is what I have found out. remove_attachment! is meant to remove the image from S3, but is not meant to remove the uploader object in the attachment column, in the db. This is the normal behavior of Carrierwave.
Jnicklas provided a test spect at https://github.com/jnicklas/carrierwave/commit/ecabc618d0fce22c1931c6d2eb134886e3b60e4c which uses #doc.remove_image = true. This is the key, because when one submits a form to remove an attachment / image / photo / whatever. They normally include a check box that looks like:
<input type="checkbox" value="1" name="user[remove_attachment]" id="user_remove_attachment">
Which can be rendered with the helper tag as:
<%= f.check_box :remove_attachment %>
If the check box is clicked and the form is submitted. Params will look something like:
{"utf8"=>"✓", "_method"=>"put", ....., "user"=>{"remove_attachment"=>"1"}, "controller"=>"das....}
Rails will interpret this as #user.remove_attachment = true to clear the db column and also trigger .remove_attachment! to remove the file from S3.
Also worth noting. If attr_accessible is defined in the User model. Then it must have :attachment, :remove_attachment as well.
Hope this helps someone out.