Conditional versions in Carrierwave - conditional-statements

I'm working on doing a simple rotate+resize on an uploaded image but only if it is landscape format. Otherwise, I just want the image resized. I also want to do this while keeping the version name the same (not have a "medium" and a "medium_rotated") So far I have the rotate working but the problem is if I upload a non-landscape image, it doesn't work at all. It only works for landscaped images. Here's the relevant parts of my code so far. Any ideas?
-Benny
class FloorPlanPhotoUploader < CarrierWave::Uploader::Base
....
version :medium, :if => :is_landscape? do
process :rotate_cw
end
version :medium do
process :resize_and_pad => [ 260, 360, :white, 'Center']
end
def is_landscape? picture
file = (picture.is_a? CarrierWave::Storage::Fog::File) ? picture.public_url : picture.file
image = MiniMagick::Image.open(file)
image[:width] > image[:height]
end
def rotate_cw
manipulate! do |img|
img.rotate "90>"
img = yield(img) if block_given?
img
end
end
....
end

The problem is that you've defined the :medium version twice. It's hitting the:
..., :if => is_landscape?
portion, which for non-landscape images returns false. As a result, nothing is done. The second declaration of version :medium you've got there never gets run, because you can't declare two versions with identical names, so it's just completely skipped.
What you need to do is produce just one version, named :medium, and conditionally process the clockwise rotation. Something like:
class FloorPlanPhotoUploader < CarrierWave::Uploader::Base
...
version :medium do
process :rotate_cw, :if => :is_landscape?
process :resize_and_pad => [ 260, 360, :white, 'Center']
end
...
end
You're allowed to chain multiple processing steps in a single version this way. Here is a great tutorial that goes into more depth on this topic.

Here is solution:
version :medium do
process :rotate_cw, if: ->( uploader, args ) { uploader.model.is_landscape? }
process :resize_and_pad => [ 260, 360, :white, 'Center']
end

Related

Duplicating a record with associated images using Carrierwave

I have an app which you can store order/invoices in. I'm building a simple feature where you can duplicate invoices for my customers. I wrote this method in my Order.rb model which:
Takes the invoice, duplicates the associated lineitems, adds the new OrderID into them...and does the same for associated images.
def self.duplicate_it(invoice)
new_invoice = invoice.dup
new_invoice.save
invoice.lineitems.each do |l|
new_lineitem = l.dup
new_lineitem.order_id = new_invoice.id
new_lineitem.save
end
invoice.images.each do |i|
new_image = i.dup
new_image.order_id = new_invoice.id
new_image.save
end
return new_invoice
end
Unfortunately, you can't just .dup the image because there's all this associate expiration stuff since I'm storing images on S3. Is there a way to regenerate the image maybe using its image_url?
The error I get when running this is below. Which tells me not all the associated image information is dup'd correctly.
Showing /Users/bruceackerman/Dropbox/printavo/app/views/orders/_image-display.erb where line #3 raised:
undefined method `content_type' for nil:NilClass
Extracted source (around line #3):
1: <% #order.images.each do |image| %>
2: <% if image.image && image.image.file %>
3: <% if image.image.file.content_type == "application/pdf" %>
4: <%= link_to image_tag("/images/app/pdf.jpg",
5: :class => 'invoice-image'),
6: image.image_url,
i think you can do the following
invoice.images.each do |i|
new_image = new_invoice.images.new({ order_id: new_invoice.id })
new_image.image.download!(i.image_url)
new_image.store_image!
new_image.save!
end
This is actually how I did it for each lineitem on an order:
def self.duplicate_it(invoice)
new_invoice = invoice.dup :include => {:lineitems => :images} do |original, kopy|
kopy.image = original.image if kopy.is_a?(Image)
end
new_invoice.save!
return new_invoice
end
It is a bit late however this is my solution. I have had far too many problems with .download!
if #record.duplicable?
new_record = #record.dup
if new_record.save
#record.uploads.each do |upload|
new_image = new_record.uploads.new({ uploadable_id: new_record.id })
new_image.filename = Rails.root.join('public'+upload.filename_url).open
new_image.save!
end
end
Here is my upload.rb
class Upload < ActiveRecord::Base
belongs_to :uploadable, polymorphic: true
mount_uploader :filename, ImageUploader
end
Hope it helps!

Devise Gem and the Geocoder Gem

I am using geocoder and the devise gem. And i am trying to get coupons near user's location
Coupon Model
def index
if params[:search].present?
#coupons = Coupon.near([user_long, user_lat], 50, :order => :distance)
else
#coupons = Coupon.all
end
end
Application Helper
I have defined the user_long and user_lat
def user_long
current_user.longitude
end
def user_lat
current_user.latitude
end
Devise Gem
I have tried to use the devise gem helper to get the values like so
Coupon Model
def index
if params[:search].present?
#coupons = Coupon.near([current_user.longitude, current_user.latitude], 50, :order => :distance)
else
#coupons = Coupon.all
end
end
I am hitting the walls and celling with this. Can someone help out, i know this is newbie question for but i can't solve it so save my life?
You are not seeing anything on the index page because your #coupons array is empty:
#coupons = Coupon.near([current_user.longitude, current_user.latitude], 50, :order => :distance)
In development log (in the same window where rails server is running, if you are running the rails server from console), you should check out the SQL query generated for CouponsController#index action.
Assuming you defined your 'near' query like this:
class Coupon
scope :near, lambda { |longitude, latitude| some logic...
end
You can debug this 'near' method using "rails console" like this:
rails console
> Coupon.near(10, 20)
etc..
My mistake was that i that i had the longitude before that latitude, It was taking away the logic
This works.
def index
#coupons = Coupon.near([current_user.latitude, current_user.longitude], 50, :order => :distance)
end

feed single .jpg file true carrierwave?

Would it be possible to feed a single.jpg true carrierwave?
Using jpegcam Im generating a temp.jpg and would like to feed this in carrierwave
so it gets stored in the photos table and generate the thumbnails based on the /uploaders/photo_uploader.rb
Any way to feed a single jpg to carrierwave?
def upload
File.open(upload_path, 'w:ASCII-8BIT') do |f|
f.write request.raw_post
end
render :text => "ok"
end
private
def upload_path # is used in upload and create
file_name = ("webcam_1.jpg")
File.join(::Rails.root.to_s, 'public', 'uploads', file_name)
Photo.create(:file => File.open("#{Rails.root}/public/uploads/#{file_name}"))
end
If I understand your question correctly, you just want to create a Photo from a file? Assuming your Photo class has an 'image' field that Carrierwave is using, that would be this:
Photo.create(:image => File.open("#{Rails.root}/public/uploads/#{file_name}"))

Rails 3 - Merge query options

I have this method form a Rails 2.3.4 app:
def self.find_all_colored(query, options={})
finder_options = {:conditions => "color = #{query}"}.merge(options)
Car.find(:all, finder_options)
end
With which I can do:
Car.find_all_colored("red", :limit => 5)
But I am having a really bad time trying to get that to work in Rails 3.1.1, by now I can make it work but without the .merge(options), if I add that part:
def self.find_all_colored(query, options={})
Car.where("color = #{query}").merge(options)
end
I get this error:
undefined method `default_scoped?' for {:limit=>5}:Hash
I've googled and searched in stackoverflow.com but no luck...thanks!
Try the following:
def self.find_all_colored(query, options={})
self.all({:conditions => {:color => query}}.merge(options))
end

How can I map between strings and attributes automatically?

I have a tiny logical error in my code somewhere and I can't figure out exactly what the problem is. Let's start from the beginning. I have the following extension that my order class uses.
class ActiveRecord::Base
def self.has_statuses(*status_names)
validates :status,
:presence => true,
:inclusion => { :in => status_names}
status_names.each do |status_name|
scope "all_#{status_name}", where(status: status_name)
end
status_names.each do |status_name|
define_method "#{status_name}?" do
status == status_name
end
end
end
end
This works great for the queries and initial setting of "statuses".
require "#{Rails.root}/lib/active_record_extensions"
class Order < ActiveRecord::Base
has_statuses :created, :in_progress, :approved, :rejected, :shipped
after_initialize :init
attr_accessible :store_id, :user_id, :order_reference, :sales_person
private
def init
if new_record?
self.status = :created
end
end
end
Now I set a status initially and that works great. No problems at all and I can save my new order as expected. Updating the order on the other hand is not working. I get a message saying:
"Status is not included in the list"
When I check it seems that order.status == 'created' and it's trying to match against :created. I tried setting the has_statuses 'created', 'in_progress' etc but couldn't get some of the other things to work.
Anyway to automatically map between string/attribute?
from your description, looks like you're comparing a string to a symbol. Probably need to add:
define_method "#{status_name}=" do
self.status = status_name.to_sym
end
or do a #to_s on the status_names