12/08/2018, 14:19

Module, included callback

MODULE Ruby module cho phép chúng ta gom các methods lại thành một nhóm và sau đó các methods này có thể được sử dụng bằng cách include module chứa chúng vào trong bất kỳ module/class nào khác. Vì ta không thể khởi tạo trực tiếp đối tượng của lớp Module, vì vậy muốn sử dụng được các method ...

MODULE

Ruby module cho phép chúng ta gom các methods lại thành một nhóm và sau đó các methods này có thể được sử dụng bằng cách include module chứa chúng vào trong bất kỳ module/class nào khác.

Vì ta không thể khởi tạo trực tiếp đối tượng của lớp Module, vì vậy muốn sử dụng được các method trong module, ta cần include module vào trong class thông qua method include và sử dụng đối tượng của class để gọi ra các method trong module. Ví dụ sau minh họa cho cách sử dụng của module:

Screenshot from 2016-11-30 14:10:46.png

INCLUDED CALLBACK

Ruby cung cấp một hàm callback có tên included cho module. Hàm callback này sẽ được gọi mỗi khi module được included vào một module hoặc class khác. Ví dụ sau sẽ minh họa cho cách dùng của hàm callback này.

123.png

1234.png

VẤN ĐỀ GẶP PHẢI KHI SỬ DỤNG MODULE

Hạn chế của việc một class include một module đó là class đó chỉ có thể truy cập các instance methods của module mà không thể truy cập tới các class methods. Xét ví dụ sau:

module WarmUp
  def push_ups
    #..
  end

  class << self
    def run_5_round
      #..
    end
  end
end

class Football < ActiveRecord::Base
  include WarmUp
end
$ rails c

$ puts Football.new.push_ups #OK

$ puts Football.run_5_round #NoMethodError

Như đã thấy, ta nhận được lỗi NoMethodError khi cố gắng truy cập class method của module WarmUp từ class Football. Một cách giải quyết vấn đề này là ta nhóm các class methods trong một module và extend nó trong included callback, đồng thời trong callback này, ta có thể viết các method về validates, quan hệ, scope.. để các model có thể tái sử dụng

# ../model/concerns/warm_up.rb
module WarmUp
  def self.included klass
    klass.extend ModuleMethods

    klass.class_eval do
      has_many :players
      validates :number_of_player, presence: true
    end
  end

  module ModuleMethods
    def run_5_round
      #..
    end
  end

  def push_ups
    #..
  end
end

# ../model/football.rb
class Football < ActiveRecord::Base
  include WarmUp
end

# ../model/kungfu.rb
class Kungfu < ActiveRecord::Base
  include WarmUp
end
0