ActiveRecord에서 기본값을 어떻게 설정합니까?
나는 추악하고 복잡한 코드 덩어리를 설명하는 Pratik의 게시물을 참조하십시오 : http://m.onkey.org/2007/7/24/how-to-set-default-values-in-your-model
class Item < ActiveRecord::Base
def initialize_with_defaults(attrs = nil, &block)
initialize_without_defaults(attrs) do
setter = lambda { |key, value| self.send("#{key.to_s}=", value) unless
!attrs.nil? && attrs.keys.map(&:to_s).include?(key.to_s) }
setter.call('scheduler_type', 'hotseat')
yield self if block_given?
end
end
alias_method_chain :initialize, :defaults
end
나는 다음과 같은 예제가 인터넷을 통해 보았습니다.
def initialize
super
self.status = ACTIVE unless self.status
end
과
def after_initialize
return unless new_record?
self.status = ACTIVE
end
또한 사람들이 마이그레이션에 넣는 것을 보았지만 모델 코드에 정의 된 것을 보았습니다.
ActiveRecord 모델에서 필드의 기본값을 설정하는 정식 방법이 있습니까?
답변
사용 가능한 각 방법에는 몇 가지 문제가 있지만 after_initialize
콜백 을 정의 하면 다음과 같은 이유로 갈 수 있습니다.
default_scope
새 모델의 값을 초기화하지만 모델을 찾는 범위가됩니다. 일부 숫자를 0으로 초기화 하려면 원하는 것이 아닙니다 .- 마이그레이션에서 기본값을 정의하는 것도 시간의 일부로 작동합니다. 이미 언급했듯이 Model.new를 호출하면 작동 하지 않습니다 .
- 재정의
initialize
는 효과가 있지만 전화하는 것을 잊지 마십시오super
! - phusion과 같은 플러그인을 사용하는 것은 약간 어리 석습니다. 이것은 루비입니다. 기본값을 초기화하기 위해 플러그인이 정말로 필요합니까?
- Rails 3에서는 재정의
after_initialize
가 더 이상 사용되지 않습니다. Railsafter_initialize
3.0.3에서 재정의 하면 콘솔에 다음 경고가 표시됩니다.
DEPRECATION 경고 : Base # after_initialize가 사용되지 않으므로 대신 Base.after_initialize : method를 사용하십시오. (/ Users / me / myapp / app / models / my_model : 15에서 호출)
따라서 after_initialize
콜백을 작성하면 다음 과 같이 연결에서 기본값을 설정할 수 있을뿐만 아니라 기본 속성 을 사용할 수 있습니다.
class Person < ActiveRecord::Base
has_one :address
after_initialize :init
def init
self.number ||= 0.0 #will set the default value only if it's nil
self.address ||= build_address #let's you set a default association
end
end
이제 모델의 초기화를 찾을 수있는 곳이 한 곳 뿐입니다 . 누군가가 더 나은 방법을 찾을 때 까지이 방법을 사용하고 있습니다.
주의 사항 :
-
부울 필드의 경우 다음을 수행하십시오.
self.bool_field = true if self.bool_field.nil?
자세한 내용은이 답변에 대한 Paul Russell의 의견을 참조하십시오.
-
모델에 대한 열의 하위 집합 만 선택하는 경우 (예 :
select
와 같은 쿼리에서 사용Person.select(:firstname, :lastname).all
) 메서드가 절 에 포함되지 않은 열에 액세스하는MissingAttributeError
경우 얻을 수 있습니다. 다음과 같이이 경우를 막을 수 있습니다.init
select
self.number ||= 0.0 if self.has_attribute? :number
부울 열의 경우 …
self.bool_field = true if (self.has_attribute? :bool_value) && self.bool_field.nil?
또한 구문은 Rails 3.2 이전과 다릅니다 (아래 Cliff Darling의 의견 참조).
답변
레일 5+
모델 내 에서 속성 방법을 사용할 수 있습니다 ( 예 :
class Account < ApplicationRecord
attribute :locale, :string, default: 'en'
end
default
매개 변수에 람다를 전달할 수도 있습니다 . 예:
attribute :uuid, UuidType.new, default: -> { SecureRandom.uuid }
답변
마이그레이션을 통해 데이터베이스에 기본값을 넣습니다 ( :default
각 열 정의에 옵션을 에 기본값을 설정하고 Active Record에서 이러한 값을 사용하여 각 속성에 대한 기본값을 설정하도록합니다.
IMHO,이 접근법은 AR의 원칙과 일치합니다 : 컨벤션에 대한 컨벤션, DRY, 테이블 정의는 다른 방식이 아니라 모델을 주도합니다.
모델이 아니라 마이그레이션에서는 기본값이 여전히 애플리케이션 (Ruby) 코드에 있습니다.
답변
데이터베이스 스키마에서 기본값을 정의하여 일부 간단한 경우를 처리 할 수 있지만 계산 된 값과 다른 모델의 키를 포함하여 여러 까다로운 경우는 처리하지 않습니다. 이 경우 나는 이것을한다 :
after_initialize :defaults
def defaults
unless persisted?
self.extras||={}
self.other_stuff||="This stuff"
self.assoc = [OtherModel.find_by_name('special')]
end
end
after_initialize를 사용하기로 결정했지만 새로운 객체 또는 생성 된 객체에만 적용되는 것을 원하지 않습니다. after_new 콜백 이이 명백한 유스 케이스에 제공되지 않는 것이 거의 충격적이지만 객체가 이미 지속되어 객체가 새로운 것이 아님을 확인하여 확인했습니다.
Brad Murray의 답변을 본 후 조건이 콜백 요청으로 이동하면 더 깨끗합니다.
after_initialize :defaults, unless: :persisted?
# ":if => :new_record?" is equivalent in this context
def defaults
self.extras||={}
self.other_stuff||="This stuff"
self.assoc = [OtherModel.find_by_name('special')]
end
답변
after_initialize 콜백 패턴은 다음을 수행하여 간단히 개선 할 수 있습니다.
after_initialize :some_method_goes_here, :if => :new_record?
다음 코드는 관련 코드를 포함하지 않고 초기 레코드를 읽는 경우 미묘한 n + 1을 트리거하기 때문에 초기화 코드가 연관을 처리해야하는 경우 이는 사소한 이점이 있습니다.
class Account
has_one :config
after_initialize :init_config
def init_config
self.config ||= build_config
end
end
답변
Phusion 녀석은 이것에 대한 멋진 플러그인 을 가지고 있습니다 .
답변
제안 된 답변보다 훨씬 더 좋고 깨끗한 잠재적 방법은 다음과 같이 접근자를 덮어 쓰는 것입니다.
def status
self['status'] || ACTIVE
end
ActiveRecord :: Base 설명서의 “기본 접근 자 덮어 쓰기” 및 self 사용에 대한 자세한 내용은 StackOverflow를 참조하십시오 .