2012-03-15 21 views
10

私は、画像をモジュールにトリミングするために必要なロジックを抽象化して、モデルを乱さないようにしようとしています。コードは、私が拡張使用する必要があることと思われる私のモデルにこれを含めるにはhttp://railscasts.com/episodes/182-cropping-imagesruby​​ include vs extend

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 

に基づいています。私はクラスメソッドを含めるための拡張だと思った。私はJavaの背景からです - 私は基本的にクラスの上に静的メソッドを作成拡張を使用すると思った。

class Website < ActiveRecord::Base 
    extend CroppableImage 
    croppable_image :logo, :footer_image 

- 私が本当に望んでいますが、インスタンス・メソッドを作成することであることを、次に思わ

に動作します。

class Website < ActiveRecord::Base 
    include CroppableImage 
    croppable_image :logo, :footer_image 

- これは

を「#ために未定義のメソッド `croppable_image」」エラーがスローされます誰もが起こっていただきましたし、私には、あるいはこのような場合には延長使用すべきか説明していただけます。オブジェクトのシングルトンクラスにモジュールを含み(およびモジュールのインスタンスメソッドを使用すると、拡張クラスのシングルトンメソッドことになり)extend - おかげでみんな

+1

を用いる延在し含む 例のためのコールバックは' extend'は、クラスメソッドとしてメソッドを追加しました。 – zeacuss

答えて

13

extend Mは内部class << self; include M; endに似ています。あなたはクラス定義のコンテキストでcroppable_imageを呼び出すので、croppable_imageあなたのケースで

ClassクラスのインスタンスメソッドまたはWebsiteクラスのシングルトンメソッドでなければなりません。

あなたがCroppableImageを拡張を使用してモジュールCroppableImageWebsiteクラスを拡張する必要があります理由はここにある - それはWebsiteクラスのシングルトンメソッドとしてインスタンスメソッドcroppable_imageを追加します。

+0

私は最終的にそれを得ると思います。 croppable_imageはクラスメソッドですが、define_methodで定義されたメソッドはインスタンスメソッドになります。私はちょうどhttp://stackoverflow.com/questions/302789/can-i-define-method-in-rails-modelsを読みました。ありがとうございました – Nick

+0

@Nick、はい、 'define_method'は' Website'クラスで実行され、 'define_method'は' Website'クラスの* instance methods *を追加します。 –

7

両方のロジックを併用することができます。 `include`がインスタンスメソッドとしてメソッドを追加しながら Rubyは含まコールバック

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 
+0

それを行う滑らかな方法;) – Aghyad