Removing Carrierwave previously uploaded file messes up new file processing - ruby-on-rails-3

I'm using https://github.com/jnicklas/carrierwave with AWS3 to upload my app file to Amazon. I've got an Employee model with an image column (think of it as the employee profile picture) which has an uploader mounted to it:
class Employee < ActiveRecord::Base
mount_uploader :image, ProfileImageUploader
...
end
Whenever an employee updates its profile picture, I want the previous one to be deleted. In order to do this, I've got the following :after_update callback in my Employee model:
class Employee < ActiveRecord::Base
...
after_update :remove_changed_image, :if => 'self.image_changed?'
def remove_changed_image
self.image_was.remove!
end
end
This successfully deletes the previous file. But I'm also processing the pictures that get uploaded. In my Uploder I have the following:
class ProfileImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
# Create different versions of your uploaded files:
version :thumb do
process :resize_to_limit => [300, 300]
end
...
end
The problem is that the new files are not being processed at all. Only one version, the unprocessed one, gets uploaded, whereas if I don't remove the previous image, then all works as it should (many versions are uploaded).
Any help? Thanks!

The problem is with the after_update callback. It is called after the object is saved, thus deleting the newly attached file. You need to call #employee.remove_image before saving the object.

Related

Using Paper Trail to find the user who updated the current version of the model

The project I am working is using the Paper Trail gem to store previous versions of certain models.
I'm using this to display an audit history page on the models view page which shows what was changed between model updates and who changed it. This is working fine for the previous versions, but I would also like to show who updated the current version of the model.
Is there a version of the whodunnit command to find who updated the model to its current state?
I figured Paper Trail must store it somewhere for the current version otherwise it wouldn't know for when it populates the model.versions array on the next update.
I've searched on Stack Overflow and even started looking through the gems code, but I couldn't work out how it stores whodunnit for the current_version.
//Returns true if this widget(object) is the current, live one; or false if it is from a previous version.
widget.live?
//Return the version this widget was reified from, or nil if it is live.
You can customise the name of the method.
widget.version
If object is live then version is nil
You can fetch the last version as
widget.versions.last.whodunnit
class ApplicationController < ActionController::Base
def user_for_paper_trail
user_signed_in? ? current_user : 'Guest'
end
def info_for_paper_trail
{ user_id: current_user.id } if user_signed_in?
end
end
# config/initializers/paper_trail.rb
class Version < ActiveRecord::Base
attr_accessible :user_id
end

rails migrating from paperclip to carrierwave_direct

I have migrated from Paperclip to Carrierwave, and using Carrierwave_direct to upload images directly to S3.
class User < ActiveRecord::Base
mount_uploader :profile_picture, ProfilePictureUploader, :mount_on => :profile_picture_file_name
So, in my schema, I don't have column profile_picture but profile_picture_file_name in my users table.
This creates problem when I am trying to create the #uploader instance variable
class ProfilePictureController < ApplicationController
def show
#user=current_user
#uploader = #user.profile_picture_file_name
#uploader.success_action_redirect = crop_url
end
This throws an error, when a user is trying to upload the Profile Image,
undefined method `success_action_redirect=' for nil:NilClass
I guess this could fix it:
#uploader = #user.profile_picture

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?

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.