I am trying to abstract some of the logic required for cropping images into a module so that its not messing up my models. The code is based on http://railscasts.com/episodes/182-cropping-images
module CroppableImage
def croppable_image(*image_names)
image_names.each do |image_name|
define_method "#{image_name}_sizes" do
{ :cropped => read_attribute("#{image_name}_size").to_s, :large => "800x800>" }
end
define_method "#{image_name}_geometry" do |style|
style ||= :original
@geometry ||= {}
@geometry[style] ||= Paperclip::Geometry.from_file(eval "#{image_name}.path(style)")
end
define_method "#{image_name}_aspect_ratio" do
width, height = read_attribute("#{image_name}_size").split("x")
width.to_f / height.to_f
end
private
define_method "reprocess_#{image_name}" do
eval "#{image_name}.reprocess!"
end
end
end
end
To include this into my model it seems that I have to use extend. I thought extend was for including class methods. I am from a java background - I thought using extend basically created static method on the class.
class Website < ActiveRecord::Base
extend CroppableImage
croppable_image :logo, :footer_image
-- this works
It seems then that what I am really wanting is to create instance methods.
class Website < ActiveRecord::Base
include CroppableImage
croppable_image :logo, :footer_image
-- This throws the error "undefined method `croppable_image' for #"
Can anyone please explain whats going on and if I should be using include or extend in this case. Thanks guys
The only difference is where in the ancestor chain the module is added. With include , the module is added after the class in the ancestor chain. With prepend, the module is added before the class in the ancestor chain.
With included a class simply includes the module. It allows the module to be one neat package: instance methods, class methods, and setup code. Without included a module can only inject instance methods. Class methods would have to be added separately, as well as executing any setup code.
The Ruby class Class inherits from Module and adds things like instantiation, properties, etc – all things you would normally think a class would have. Because Module is literally an ancestor of Class , this means Modules can be treated like classes in some ways. As mentioned, you can find Module in the array Class.
What is the difference between a class and a module? Modules are collections of methods and constants. They cannot generate instances. Classes may generate instances (objects), and have per-instance state (instance variables).
extend M
internally is similar to class << self; include M; end
- extend
includes module into singleton class of an object (and makes instance methods of the module to be a singleton methods of a class you extend).
In your case you call croppable_image
in the context of a class definition and thus croppable_image
should be an instance method of a Class
class or a singleton method of Website
class.
This is why you should extend Website
class with a module CroppableImage
by using extend CroppableImage - it adds instance method croppable_image
as a singleton method of Website
class.
you can use both logic together. Ruby has callbacks for extend and include Example of using included callback
module CroppableImage
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def bar
puts 'class method'
end
end
def foo
puts 'instance method'
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With