Saturday, 11 October 2014

Crop, zoom and rotate image using carrierwave

Crop, zoom and rotate image using carrierwave


We already have a good reading about cropping in rails using jcrop from ryanbates railscast (http://railscasts.com/episodes/182-cropping-images?view=asciicast). But in my recent rails project I need functionality to rotate and crop zoomed image. So I made following changes that might help others.

## My original image :-



First of all we need carrierwave to upload images and mini_magick to manipulate images. So add following gems in your Gemfile.

##/Gemfile

gem 'carrierwave'
gem 'mini_magick'

To crop, zoom and rotate image we need to add 'cropzoom' file and 'custom.min' file in assets. Find here https://github.com/cropzoom/cropzoom

Following assetes changes required :

##/app/assets/javascripts/application.js

//= require jquery.cropzoom
//= require jquery-ui-1.10.3

##/app/assets/stylesheets/application.css

*= require jquery-ui-1.10.3.custom.min
*= require jquery.cropzoom

Now, to get coordinates of crop, zoom or rotated image we need to set attr_accessor for :
Cropped image coordinates : crop_x, crop_y, crop_w, crop_h
Zoomed image coordinates : zoom_x, zoom_y, zoom_w, zoom_h
Dragged image coordinates : drag_x, drag_y
Rotation angle : rotation_angle

So, my model looks like this :- 

/app/models/user.rb

class User < ActiveRecord::Base

mount_uploader :image, ImageUploader
attr_accessor :crop_x, :crop_y, :crop_w, :crop_h, :rotation_angle, :zoom_w, :zoom_h, :zoom_x, :zoom_y, :drag_x, :drag_y

Changes required in image crop view.


##/app/views/users/crop.html.erb

# Hide the original image.

<%= image_tag @user.image.url, class: 'img-responsive hide_img' %>

# Container where we will crop, zoom and rotate image
<div id='crop_container'></div>

<% form_for @user do |f| %>
  <% for attribute in [:zoom_w, :zoom_h, :zoom_x, :zoom_y, :drag_x, :drag_y, :rotation_angle, :crop_x, :crop_y, :crop_w, :crop_h] %>
    <%= f.hidden_field attribute, :id => attribute %>
  <% end %>
  <p><%= f.submit "Crop" %></p>
<% end %>

# Initialize cropzoom container

<script>
  $(document).ready(function() {
    var cropzoom = $('#crop_container').cropzoom({ 
      width:300,
      height:300,
      bgColor: '#CCC',
      enableRotation:true,
      enableZoom:true,
      zoomSteps:10,
      rotationSteps:10,
      selector:{
        centered:false,
        startWithOverlay: true,
        borderColor:'blue',
        borderColorHover:'yellow'
      },
      image:{
        source:$('.img-responsive').attr('src'),
        width:768,
        height:768,
        minZoom: 20,
        onRotate: function(imageObject, rotate_angle){
          // Get rotatation angle
          $("#rotation_angle").val(rotate_angle);
        },
        onZoom: function(imageObject, dimensions){
          // Get zoom coordinates
          $('#zoom_w').val(dimensions.w);
          $('#zoom_h').val(dimensions.h);
          $('#zoom_x').val(dimensions.posX);
          $('#zoom_y').val(dimensions.posY);
          // Set drag coordinates to zero when image is zoomed
          $('#drag_x').val(0);
          $('#drag_y').val(0);
        },
        onImageDrag: function(imageObject, position){
          // Get dragged image coordinates
          $('#drag_x').val(position.posX);
          $('#drag_y').val(position.posY);
          // Set zoom x-y coordinates to zero when image is dragged
          $('#zoom_x').val(0);
          $('#zoom_y').val(0);
        }
      }
    });
  });
  
  // Get cropped image coordinates

  $(document).on('click', 'input[type="submit"]', function() {
    var get_html = $('#infoSelector').html()
    var get_array = get_html.split('|')
    var get_x_y_coords_array = get_array[0].split('-')
    var get_w_h_coords_array = get_array[1].split('-')
    var get_x_coord = get_x_y_coords_array[0].split(':')[1]
    var get_y_coord = get_x_y_coords_array[1].split(':')[1]
    var get_w_coord = get_w_h_coords_array[0].split(':')[1]
    var get_h_coord = get_w_h_coords_array[1].split(':')[1]
    $('#crop_x').val(get_x_coord);
    $('#crop_y').val(get_y_coord);
    $('#crop_w').val(get_w_coord);
    $('#crop_h').val(get_h_coord);
  });
</script>

Crop view looks like this :-




Note :- In documentation of cropzoom plugin 'onImageDrag()' shuold have two values, but it have only one. Line no. 182 in my case

So, We need to change in jquery.cropzoom.js.

##/app/assets/javascripts/jquery.cropzoom.js

Change in $($image).draggable() function.

Change :- 
  if ($options.image.onImageDrag != null)
    $options.image.onImageDrag($image);
To :-
  if ($options.image.onImageDrag != null)
  $options.image.onImageDrag($image, getData('image'));

Required controller changes.

##/app/controllers/users_controller.rb

@user = User.find(params[:id])

#If we get image from remotely
@user.remote_image_url = User.first.image

if @user.update_attributes(params[:user])
  if params[:user][:crop_x].present?
    @user.image = @user.image.resize_and_crop
    @user.save!
    @user.image.recreate_versions!
  end
end

##/app/assets/stylesheets/custom.css

// To hide image 

.hide_img {
  display: none;
}

Now, finally changes are required in carrierwave uploader.

##/app/uploaders/image_uploader.rb

include CarrierWave::MiniMagick

version :custom_crop do
  process :resize_and_crop
end

def resize_and_crop
  if model.class.to_s == "User"
    if model.crop_x.present?
      manipulate! do |img| 
        w = model.crop_w.to_i
        h = model.crop_h.to_i
        
        // Set x-y coordinates of cropped image.
        x = model.zoom_x.to_i >= 0 ? (model.crop_x.to_i - model.zoom_x.to_i) : (model.zoom_x.to_i.abs + model.crop_x.to_i)
        y = model.zoom_y.to_i >= 0 ? (model.crop_y.to_i - model.zoom_y.to_i) : (model.zoom_y.to_i.abs + model.crop_y.to_i)
        x = model.drag_x.to_i >= 0 ? (x - model.drag_x.to_i) : (model.drag_x.to_i.to_i.abs + x) 
        y = model.drag_y.to_i >= 0 ? (y - model.drag_y.to_i) : (model.drag_y.to_i.to_i.abs + y) 

        img.combine_options do |i|
          // First we need to resize image with zoomed image. For more details you can find here "https://github.com/minimagick/minimagick"
          i.resize "#{model.zoom_w.to_i}x#{model.zoom_h.to_i}+#{model.zoom_x.to_i}+#{model.zoom_y.to_i}^\!"
          // Rotate zoomed image
          i.rotate(model.rotation_angle.to_i)
          // Crop zoomed and rotated image
          i.crop "#{w}x#{h}+#{x}+#{y}"
        end
        img
      end
    end
  end
end


## Final output is :-


Friday, 10 October 2014

CanCan ActiveModel::ForbiddenAttributesError with Rails 4

1) Replace gem in gem file
Use gem 'cancancan', '~> 1.9', in place of gem 'cancan'

2) In your controller use like this:
load_and_authorize_resource param_method: :my_sanitizer 

my_sanitizer is a example. It is your controller permit params method, similar like:

def my_sanitizer
    params.require(:article).permit(:name)
 end

Thursday, 9 October 2014

Access Control In Ruby

RUBY

What is access control?


Access control provide restriction to access sensible parts of your code from other. This feature enables you to hide the implementation details of your code, and specify a preferred way by which that code can be accessed and used.

Object is only thing with which we can make changes in application. The only way to change an object's state in Ruby is calling one of its methods.

Good rule of thumb in access control:
"never to expose methods that could leave an object in an invalid state"

In Ruby, the inheritance hierarchy or the package/module don't really enter into the equation in context of access control like any other language, it is rather all about which object is the receiver of a particular method call.

Ruby gives you three levels of protection:

Public methods : Public methods can be called by everyone - no access control is enforced. Methods are public by default, anyone can call them. Can be accessed with implicit & explicit receiver. But initialize method is always private.

Protected methods : Protected methods can be only called by objects of the defining class and its subclasses. Can be accessed with implicit & explicit receiver. However, usage of protected is limited.

Private methods : Private methods cannot be called with an explicit receiver - the receiver is always self. This means that private methods can be called only in the context of the current object. We cannot call another object's private methods.

So now implicit & explicit receiver comes in picture.

What is implicit & explicit calling ?
In explicit calling we need to provide reference of object, on which method should be call. We provide this using self or using class instance. But in implicit calling we do not need to provide any reference to object, it will automatically take self as referencing object.

Confused confused confused :(
If we take example from real world then it might be easy to understand. If I ask some one to purchase a book then without any specification that person will go to bookshop not to hospital or medical. This we can consider as implicit calling. Now if I ask that person to purchase book from specific vendor (ABC shop). Then he will go to that specific shop to purchase that book. This we call as explicit calling.

Lets see below code to understand what Implicit and Explicit calling is


class Test
  def method1
    # Implicit calling
    method2
  end

  def method2
  end
end

t = Test.new
# Explicit calling
t.method1



We will study further about private and protected access modifier.

How we can define a method private or protected in ruby?
There are two ways to define a method private or protected.


class MyClass

  def method1          # this method is public
  end

  protected

    def method2        # this method is protected
    end

  private

    def method3        # this method is private
    end

end


class MyClass

  def method1          # this method is public
  end

  def method2
  end

  def method3
  end

  protected :method2   # this method is protected

  private :method3     # this method is private
end

Lets run below example.


class MyClass
  def method1
    self.private1
  end

  private

  def private1
    puts "Hello I am Private"
  end
end

MyClass.new.method1

Running this produces the following noMethodError:


in `method1': private method `private1' called for #<XXXX> (NoMethodError)


Oh no! I missed private method receiver concept. Private method can be called only with implicit receiver. So I have changed my class like below.


class MyClass
  def method1
    private1
  end

  private

  def private1
    puts "Hello I am Private"
  end
end

MyClass.new.method1

Now run again.


Hello I am Private

I get desired output from my code. Now if I call it in subclass then.


class ClassA
  def main_method1
    method1
  end

  private
  def method1
    puts "hello from #{self.class}"
  end
end

class ClassB < ClassA
  def main_method1
    method1
  end
end

ClassA.new.main_method1
ClassB.new.main_method1

If I run this program.


hello from ClassA
hello from ClassB

Get desired result. "This means we can call a private method from within a class it is declared in as well as all subclasses of this class"

We can not call private method with explicit receiver not even with self. So changing previous example accordingly.


class ClassA
  def main_method1
    method1
  end

  private
  def method1
    puts "hello from #{self.class}"
  end
end

class ClassB < ClassA
  def main_method1
    self.method1
  end
end

ClassA.new.main_method1
ClassB.new.main_method1

Output :


hello from classA
`main_method1': private method `method1' called for #<XXXX> (NoMethodError)

Now Moving to protected method.
protected methods can be called by any instance of the defining class or its subclasses.

So changing examples for protected method.


class MyClass
  def method1
    protected1
  end

  def method2
    self.protected2
  end

  protected

  def protected1
    puts "Hello I am Protected1"
  end

  def protected2
    puts "Hello I am Protected2"
  end
end

MyClass.new.method1
MyClass.new.method2

Output:


Hello I am Protected1
Hello I am Protected2

Similarly for subclass:


class ClassA
  def main_method1
    method1
  end

  protected
  def method1
    puts "hello from #{self.class}"
  end
end

class ClassB < ClassA
  def main_method1
    self.method1
  end
end

ClassA.new.main_method1
ClassB.new.main_method1

Output:


hello from ClassA
hello from ClassB

So no change in output.

Now I added another class C


class ClassC < ClassA
  def main_method1
    ClassB.new.method1
  end
end

ClassC.new.main_method1

Run it and output is :


hello from ClassB


Why we need Protected ??

why we need protected if we can call a method explicitely why we need implicit call to a method.
If private method is so secure why we need one more level of access with protected in ruby.

I found my solution when I try to compaire two objects of same class. This can not achive with explicit reciever(Private Method).


class Person
  def initialize(number)
    @number = number
  end

  def number
    @number
  end

  def compare_number(c)
    if c.number > number
      "The second number is bigger."
    else
      "The second number is the same or smaller."
    end
  end

  protected :number

end

first = Person.new(25)
second = Person.new(34)

puts first.compare_number(second)

Output is:


The second number is bigger.

We cannot accomplish  this with private method only and public method are not secure for such methods. So It's clear protected methods are equally important in ruby as private.