어떤 모듈을 include 하거나 extend하는 것을 믹스인 이라고 했다. 믹스인은 다른 클래스에 추가하는 코드의 세트 이고, 모듈은 메서드와 상수의 모음이다.
dry한 코드를 만들때 보통 공통 로직을 모듈로 빼고, 필요한 클래스에서 그 모듈을 포함시켜 사용한다.
모듈로 믹스인을 사용하다 보면 include와 extend 를 동시에 해야할 때가 있다.
간단한 예로 클래스 메소드와 인스턴스 메소드를 한 모듈에서 다룰 때.
module SomeThing
def included
"iii"
end
def extended
"eee"
end
end
class SomeClass
include SomeThing
extend SomeThing
end
위 코드는 문제 없이 실행 되지만, 모듈의 두 메소드가 클래스 메서드와 인스턴스 메소드로 동시에 등록? 되어버리기 때문에 원하는 바는 아니다.
이것은 모듈을 믹스인할때 호출되는 훅들을 이용하면 해결 가능한데, 이 방식을 사용하기 쉽게한게 ActiveRecord::Concern
이다
모듈에서 Concern을 extend 하면
두 블록을 사용할 수 있다.
이 블록 안에 있는 메소드는 모듈을 include한 클래스의 클래스 메소드로 extend 된다.
class_eval을 통해 모듈을 include한 클래스에 훅이나 association을 선언할 수 있다.
해당 객체의 클래스에 함수를 추가 할 수 있다.
def add_scope_to(some_class)
some_class.class_eval do
scope :in_live, -> { where(live: true) }
def my_method
"my_method"
end
end
end
add_scope_to MyClass
Myclass.in_live
Myclass.new.my_method
정리해보자면,
module Scopable
extend ActiveSupport::Concern
included do
scope :in_live, -> { where(live: true) }
end
class_methods do
def some_class_method
'Hello'
end
end
def not_live?
!live
end
end
class Show < ApplicationRecord
include Scopable
end
같은 식으로 모듈을 구성할 수 있고, 필요에 따라 각 클래스에서 include 해서 사용할 수 있다.
여러 클래스에서 공통으로 사용 할 수 있는 scope 등을 선언할 수도 있고,
폴리몰픽 클래스와 association 이 있을 수 있는 클래스들의 로직을 묶을 수 도 있겠다.
추가로 Concern 을 extend 모듈을 다른 모듈에서 include할때 의존성 문제도 없다.
계속해서 믹스인을 이야기하고 있는데, 점점 강해지는 생각은
이번 포스팅은 깊이 생각하지 못하고 대충 썼습니다.