Ruby on Rails에서 setter 메소드를 재정의하는 올바른 방법은 무엇입니까?


184

Ruby on Rails 3.2.2를 사용하고 있으며 다음이 내 클래스 속성의 setter 메소드를 재정의하는 "적절한"/ "정확한"/ "확실한"방법인지 알고 싶습니다.

attr_accessible :attribute_name

def attribute_name=(value)
  ... # Some custom operation.

  self[:attribute_name] = value
end

위의 코드는 예상대로 작동하는 것 같습니다. 그러나 위의 코드를 사용하여 앞으로 문제가 발생하는지 또는 적어도 Ruby on Rails에서 "예상해야 할"/ "어떻게 발생할 수있는"문제가 있는지 알고 싶습니다 . 이것이 setter 메소드를 재정의하는 올바른 방법이 아닌 경우 올바른 방법은 무엇입니까?


참고 : 코드를 사용하면

attr_accessible :attribute_name

def attribute_name=(value)
  ... # Some custom operation.

  self.attribute_name = value
end

다음과 같은 오류가 발생합니다.

SystemStackError (stack level too deep):
  actionpack (3.2.2) lib/action_dispatch/middleware/reloader.rb:70

4
나는 ""적절한 "/"정확한 "/"확실한 "이라는 용어를 좋아한다. 당신이 그것을 3 가지 방법으로 줄 때 그것은 실제로 오해가 없도록 보장합니다. 잘 했어!
Jay

5
@Jay- "Fineness italianisms"; -)
Backo

2
"스택 수준이 너무 깊음"은 재귀 호출, 즉 호출 자체라는 사실을 의미합니다.
Nippysaurus

답변:


295

===================================================== ========================= 업데이트 : 2017 년 7 월 19 일

이제 Rails 문서super다음과 같이 사용하도록 제안합니다 .

class Model < ActiveRecord::Base

  def attribute_name=(value)
    # custom actions
    ###
    super(value)
  end

end

===================================================== ==========================

원래 답변

모델을 통해 액세스하는 동안 테이블의 열에 대한 setter 메소드를 대체하려는 경우이를 수행하는 방법입니다.

class Model < ActiveRecord::Base
  attr_accessible :attribute_name

  def attribute_name=(value)
    # custom actions
    ###
    write_attribute(:attribute_name, value)
    # this is same as self[:attribute_name] = value
  end

end

Rails 설명서에서 기본 접근 자 재정의를 참조하십시오 .

따라서 첫 번째 방법은 Ruby on Rails 모델에서 열 설정자를 재정의하는 올바른 방법입니다. 이러한 접근자는 모델의 속성으로 테이블의 열에 액세스하기 위해 Rails에서 이미 제공합니다. 이것을 우리는 ActiveRecord ORM 매핑이라고합니다.

또한 attr_accessible모델 상단의 접근자는 접근 자와 관련이 없음을 명심하십시오 . 그것은 완전히 다른 기능을 가지고 있습니다 ( 이 질문을보십시오 )

그러나 순수 루비에서 클래스에 대한 접근자를 정의하고 세터를 재정의하려면 다음과 같이 인스턴스 변수를 사용해야합니다.

class Person
  attr_accessor :name
end

class NewPerson < Person
  def name=(value)
    # do something
    @name = value
  end
end

무엇을 알면 이해하기가 더 쉬울 것 attr_accessor입니다. 코드 attr_accessor :name는이 두 가지 방법 (getter 및 setter)과 동일합니다.

def name # getter
  @name
end

def name=(value) #  setter
  @name = value
end

또한 두 번째 메소드는 해당 메소드 attribute_name=내 에서 동일한 메소드를 호출 할 때 무한 루프가 발생하기 때문에 실패합니다 .


9
Rails 4 attr_accessible의 경우 더 이상 존재하지 않으므로 건너 뛰면 작동합니다.
zigomir

11
왜 전화하지 super않습니까?
Nathan Lilienthal

1
접근 자와 작성자가 동적으로 만들어지기 때문에 super작동하지 않을 수 있다는 인상을 받았습니다 . 그러나 그렇지 않은 것 같습니다. 방금 확인했는데 저에게 효과적입니다. 또한,이 질문 은 똑같이 묻습니다
rubyprince

4
와 함께 큰 문제가 write_attribute있습니다. 전환은 건너 뜁니다. 알고 있어야 write_attribute거의 항상 바람직하지 않은 것 날짜와 시간대 변환을 건너 뜁니다.
팀 스콧

2
super도 잘 작동하지만 우리에게 원하지 않는 이유가 있습니다. 예를 들어 mongoid gem에는 getter 메소드를 사용하면 배열로 푸시 할 수없는 버그가 있습니다. 메모리에서 배열을 관리하는 방법이 있기 때문에 버그입니다. 또한 @name은 설정된 값을 반환하고 덮어 쓰는 메소드를 호출합니다. 그러나 위의 솔루션에서 둘 다 잘 작동합니다.
newdark-it

44

super키워드를 사용하십시오 :

def attribute_name=(value)
  super(value.some_custom_encode)
end

반대로 독자를 무시하려면 다음을 수행하십시오.

def attribute_name
  super.some_custom_decode
end

1
메소드 호출을 동일한 이름으로 제한하기 때문에 허용 된 IMO보다 응답이 좋습니다. ATTRIBUTE_NAME이 보존 상속 오버라이드 (override) 행동 =
앤드류 슈워츠

github.com/rails/rails/commit/… 이 변경으로 인해 getter 메소드를 재정의하는 것이 Rails 4.2에서 위험 해졌습니다. 이제 메소드를 호출하므로 값을 재정의하는 방법에 따라 양식에 혼란스러운 결과가 생성됩니다.
Brendon Muir

16

레일 4

테이블에 나이 속성 이 있다고 가정 해 봅시다.

def age=(dob)   
    now = Time.now.utc.to_date
    age = now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
    super(age) #must add this otherwise you need to add this thing and place the value which you want to save. 
  end

참고 : 레일 4의 새로운 코너 에는 모델에 attr_accessible 을 지정할 필요가 없습니다 . 대신 allow 메소드를 사용하여 컨트롤러 레벨에서 속성을 화이트리스트에 추가해야합니다 .


3

(적어도 ActiveRecord 관계 컬렉션의 경우) 다음 패턴이 작동한다는 것을 알았습니다.

has_many :specialties

def specialty_ids=(values)
  super values.uniq.first(3)
end

(이것은 전달 된 배열에서 처음 3 개의 중복되지 않은 항목을 가져옵니다.)


0

attr_writerattr_writer 세터 덮어 쓰기 사용 : attribute_name

  def attribute_name=(value)
    # manipulate value
    # then send result to the default setter
    super(result)
  end
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.