2016-10-07 6 views
1

제 모델에는 is_a, is_bis_c과 같은 속성이 있습니다. 기본적으로 모두 null입니다.속성을 설정하는 일반적인 방법

API를 설정해야합니다. 이러한 속성은 엄격하게 하나 또는 그룹으로 설정할 수 있습니다. API를 작성하려면 다음을 수행 할 것입니다.

def set_as_a # strictly a 
self.update_attributes!(:is_a => true, :is_b => false, :is_c => false) 
end 

def set_as_b # strictly b 
self.update_attributes!(:is_a => false, :is_b => true, :is_c => false) 
end 
... # strictly c 
def set_as_a_and_b # a and b 
self.update_attributes!(:is_a => true, :is_b => true, :is_c => false) 
end 
..... # so on 

이 방법은 효과가 있지만 효과가 없습니다. 또한 앞으로 세트에 3 개 이상의 속성이있는 경우 더 많은 반복 코드가 발생합니다. 이것을 달성하는 올바른 우아한 방법은 무엇입니까? 내가 해낸

+0

그러나 도메인 내에서이 개념은 '... enabled' 정도 같은 이름이 있어야 고르세요. 아니면 그게 정말 사실입니까? – slowjack2k

답변

4
class SettableAsABC 
    ATTRS = [:a, :b, :c] 
    METHOD_RE = /^set_as_([[:alnum:]]+?(?:_and_[[:alnum:]]+?)*)$/ 

    def method_missing(name, *args) 
    if name.to_s =~ METHOD_RE 
     trues = $1.split('_and_').map(&:to_sym) 
     attrs = Hash[ATTRS.map { |a| ["is_#{a}".to_sym, trues.include?(a)] }] 
     update_attributes(attrs) 
    else 
     super 
    end 
    end 

    def respond_to_missing?(name, include_private = false) 
    !!(name =~ METHOD_RE) || super 
    end 
end 

a = SettableAsABC.new 
a.set_as_a_and_c 

정의 된 2^N 메소드가 없으므로 루비 메타 프로그래밍이 간단합니다.

편집 : 좋은 지적, @ 스탄 판.

EDIT2 : 이전 편집에서 버그가 도입되었습니다. 이제 해결되었습니다.

EDIT3 : 약 respond_to_missing?

+1

당신은 또한'respond_to_missing을 구현해야합니까? ' – Stefan

+0

이런 식으로, +1 생각하지 마십시오. – RSB

+0

아주 좋은 접근 –

1

내가 뭔가를 오해, 그런데 왜 그냥 PARAMS?이

동적으로 여기 속성의 조합에 대한 방법을 만들려면

def set_attributes(opts = {}) 
    update_attributes!(opts) unless opts.none? 
end 
# usage 
set_attributes(is_a: false, is_b: true) 

EDIT 소요 하나의 방법을 쓸 수 있습니다 로 :

0 :

attributes = %w(a b c d) 
(1..attributes.size).flat_map { |size| attributes.combination(size).to_a }.each do |methods| 
    define_method "set_as_#{methods.join('_and_')}" do 
    update_attributes!(Hash[methods.map { |v| ["is_#{v}", true] }]) 
    end 
end 

은 다음 menthods를 생성합니다

+0

이 잘 작동합니다,하지만 난 다음 메서드를 호출하기 전에 매번 구성 할 것이다. 방법을 더 자명하게 할 수있는 가능성이 있습니까? 예를 들어'set_a_and_b'는 명확한 API입니다. 모델이 메서드 이름을 이해하고 필수 필드를 설정할 수 있다면 멋질 것입니다. 코드에 깨끗한 것이 좋다면 확실하지 않습니다. – shivam

+0

@AndreyDeineko 속성의 수가 10을 초과하면 메소드 이름이 너무 길어집니다! – RSB

+0

@AndreyDeineko가 작동하는 것처럼 보입니다. 건배 : D – shivam

0

어때?

def set_true(true_fields=[]) 
    attr_hash = {} 
    true_fields.each { |field| attr_hash[field] = true } 
    update_attributes(hash) 
end 

희망 하시겠습니까?

+0

이 작동하는 동안 메서드 이름 자체가 동적으로 값을 설정할 수 있으면 좋겠다.다시 말하지만, 심지어 가능할 지 확신 할 수 없기 때문에 질문 : – shivam

+0

메서드 이름을 동적으로 만드는 특별한 이유가 있습니까? 나는 그것이 역설적 인 주장을 쉽게함으로써 달성 될 수 있다는 것을 의미합니까? – RSB

+0

이렇게하면 청소가됩니다. 예를 들면. 레일즈 데이 API가'3.days.ago'에서 어떻게 작동하는지보십시오. 뭔가 비슷하다. – shivam

관련 문제