Rails 4, Carrierwave, Jcrop, image upload and resizing - ruby-on-rails-4

UPDATE
I moved the crop code from the uploader directly to the Notebook Model so that it gets called at least. Now, the image is getting processed. It's getting cropped in fact, to the correct width and height dimensions, but the x and y offsets are wrong. I'm using MiniMagick, not RMagick. Here is my crop_image method:
def crop_image
if crop_x.present?
image.manipulate! do |img|
x = crop_x.to_i
y = crop_y.to_i
w = crop_w.to_i
h = crop_h.to_i
z = "#{w}x#{h}+#{x}+#{y}"
img.resize "600x600"
img.crop(z)
img
end
end
image.resize_to_fill(224, 150)
end
Has something changed in Rails 4 with regards to carrierwave or imagemagick? I copied over code that I had working (in a Rails 3 application) to upload an image, crop it, and save both versions, but I can't get it to work in the Rails 4 app.
Here are the relevant parts:
class Notebook < ActiveRecord::Base
validates :title, :access, presence: true
mount_uploader :image, ImageUploader
belongs_to :user
has_many :invites
attr_accessor :crop_x, :crop_y, :crop_w, :crop_h
after_update :crop_image
def notebook_title
title
end
def user_name
user.name
end
def crop_image
image.recreate_versions! if crop_x.present?
end
end
And the recreate_versions! call accesses the image_uploader
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
include Sprockets::Rails::Helper
storage :file
include CarrierWave::MimeTypes
process :set_content_type
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Create different versions of your uploaded files:
version :large do
process resize_to_limit: [600, 600]
end
version :thumb do
process :crop
resize_to_fill(224, 150)
end
def err
raise "error here"
end
def crop
if model.crop_x.present?
resize_to_limit(600, 600)
manipulate! do |img|
x = model.crop_x.to_i
y = model.crop_y.to_i
w = model.crop_w.to_i
h = model.crop_h.to_i
size = w << 'x' << h
offset = '+' << x << '+' << y
img.crop("#{size}#{offset}")
img
end
end
end
end
I'm seeing values for crop_x, crop_y, crop_w, and crop_h. The version :thumb block does not seem to call any process methods. Even if I try to raise an error from inside the version :thumb block, it doesn't work.
If anyone can provide any info that would be great.

Related

Rails 4 - Paperclip - Pass image name as method parameter and remove it inside it

I have several paperclip attachments in a Model. I want to pass the name of it as a parameter for a method and then set it to nil.
class Campaign < ActiveRecord::Base
has_attached_file :header_image
has_attached_file :footer_image
end
class CampaignsController < ApplicationController
def remove_image(image_name)
#campaign.image_name = nil # <- I want to do something like this
end
end
How to do something like this? Is there a better way?

Rails 4 update_all syntax - Argument error

I'm getting the error:
Wrong number of arguments (2 for 1)
On my Task model when I defined my method to update all status of tasks. What is the correct syntax?
class Task < ActiveRecord::Base
belongs_to :user
def self.toggle(user, groups)
groups.each do |status, ids|
user.tasks.update_all({status: status.to_s}, {id: ids}) #=> error here
end
end
end
class GroupIdsByStatus
def self.group(options = {})
result = Hash.new {|h,k| h[k] = []}
options.reduce(result) do |buffer, (id, status)|
buffer[status.to_sym] << id
buffer
end
result
end
end
class TasksController < ApplicationController
def toggle
groups = GroupIdsByStatus.group(params[:tasks])
Task.toggle(current_user, groups)
redirect_to tasks_path
end
end
The method update_all receives a single Hash as its sole argument. You need to put all of the updates into the single argument:
user.tasks.update_all(status: status.to_s, id: ids)
# The above line of code is identical to:
# user.tasks.update_all( {status: status.to_s, id: ids} ) # < Notice the curly braces
More information on this method is shown in the Rails Relation Docs

conditional validation: if file upload, then check minimum size

I want a validation in my organisations model that runs only, when an image file is selected for upload.
app/models/organisation.rb
class Organisation < ActiveRecord::Base
validates :name, :url, :street, :city, :zipcode, presence: true
validate :validate_minimum_image_size, if: # file is selected for upload
def validate_minimum_image_size
image = MiniMagick::Image.open(picture.path)
unless image[:width] > 300 && image[:height] > 300
errors.add :image, "should be 300px minimum!"
end
end
end
Is there a way to check image size when the image file is selected to upload?
You can provide your own custom method sth like :
validate :validate_minimum_image_size, if: :file_present?
def file_present?
picture ? true : false
end

Carrierwave+Sidekiq dynamic version issue, recreate in background

When I create a new device then new version are added to my image uploader.
Then I run a job to recreate files for each MyModel record.
Sidekiq start job but it does not create files.
I use ActiveJob for declaring jobs.
This code:
MakingNewVersionImagesJob.perform_later("some_recently_added_device_name")
works fine in console after Sidekiq restart.
I think Sidekiq does not see MyModel changes.
Am I right? Is any solution here?
NOTE: it works fine when I do it directly in controller, not in background
class BaseImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
# Config/versions ...
def self.add_version(name, width, height)
version name do
process resize_to_fit: [width, height]
end
end
end
class MyModelImageUploader < BaseImageUploader
# blabla
end
class MyModel < ActiveRecord::Base
#...
mount_uploader :image, MyModelImageUploader
end
class Device < ActiveRecord::Base
after_create :add_uploaders_versions
def add_uploaders_versions
version = self.name.downcase.to_sym
MyModelImageUploader.add_version(version, self.width, self.height)
end
end
class MakingNewVersionImagesJob < ActiveJob::Base
queue_as :regular
def perform(version)
MyModel.find_each do |record|
record.image.recreate_versions!(version.to_sym)
record.save!
end
end
end
class DevicesController < ApplicationController
#...
def create
#device = Device.new(device_params)
if #device.save
MakingNewVersionImagesJob.perform_later(#device.name.downcase)
#...
end
end
end
I found out that Sidekiq/Rails both load code to own memory area, that why Sidekiq knows nothing about class changes caused on Rails side.
In my solution I switched to DelayedJob. It loads an actual Rails context.
Also, I can duplicate definition of new version in MakingNewVersionImagesJob#perform and continue to use Sidekiq.

Cannot use roo with attr_accessible

Im quite a begginer on ruby ; I ve been trying to use roo and still cannot import anything ! after hours of search, I guess problem comes from new rails version which doensn't use accessible_attributes anymore (tutorials are well done, but they all use this command...)
there is no
here is the model code i am trying to fix.
#attr_accessible :name, :price, :released_on
#validates_presence_of :price
def self.open_spreadsheet(file)
case File.extname(file.original_filename)
when '.csv' then Roo::Csv.new(file.path)
when '.xls' then Roo::Excel.new(file.path)
when '.xlsx' then Roo::Excelx.new(file.path)
else raise "Unknown file type: #{file.original_filename}"
end
def self.import(file)
spreadsheet = open_spreadsheet(file)
header = spreadsheet.row(1)
(2..spreadsheet.last_row).each do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
product = find_by_id(row["id"]) || new
product.attributes = row.to_hash.slice #(*accessible_attributes)
product.save!
end
end
(2..spreadsheet.last_row).each do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
product = find_by_id(row["id"]) || new
product.attributes = row.to_hash
product.save!
end
And make sure you've set correct permissions in your controller like that:
def product_params
params.require(:product).permit(:name, :price, :released_on)
end