ActiveRecord::Enum으로 빠지기 쉬운 실수를 피하십시오
8664 단어 Rails4루비ActiveRecord
부담없이 사용할 수 있으므로, 나누기와 적극적으로 사용하고 있습니다만 그 안인 문제가 발생했습니다.
ActiveRecord::Enum의 제공해 주는 표준으로 제공해 주는 인터페이스만으로는 *1, where의 인수로 지정하는 값은 실제로 SQL의 WHERE구로 지정되는 것이 건네주기 때문에 본래는 캐릭터 라인을 사용할 수 없다 하지만 왠지 사용할 수 있기 때문에 전달해 보면 값이 0으로 동작한다는 문제입니다
다음은 예입니다. NotifyEndpoint라는 Push 알림의 대상을 영속화하는 테이블에 대해 생각한 경우 platform으로 iPhone 용 APNS와 Android 용 GCM 등의 플랫폼을 enum으로 지정해 보겠습니다.
class NotifyEndpoint
enum platform: [:apns, :gcm]
end
# OK: newやcreateでは渡せる
endpoint = NotifyEndpoint.new(platform: :apns)
# OK: platform=メソッドにも渡せる
endpoint.platform = :gcm
# OK: apnsというスコープは定義されている
endpoints = NotifyEndpoint.apns
# NG: whereに文字列やシンボルを渡しても正しく動作しない
# しかしエラーが出ずに0としてSELECTされる!!
endpoints = NotifyEndpoint.where(platform: :gcm)
#=> SELECT * FROM notify_endoints WHERE platform = 0;
# OK: NotifyEndpoint.platformsから、enumの序数を取得してwhereで指定する
endpoints = NotifyEndpoint.where(platform: NotifyEndpoint.platforms[:gcm])
#=> SELECT * FROM notify_endoints WHERE platform = 1;
와 같이, 기본적으로는 캐릭터 라인 심볼로 enum를 취급할 수 있습니다만, 표준으로 정의되는 스코프 이외로, SELECT 하고 싶을 때는 요주의입니다. where에는 enum의 요소의 이름을 받아들이지 않습니다만 에러가 나오지 않기 때문에 어렵습니다. 정상 케이스의 테스트가 1개째의 요소 밖에 테스트하고 있지 않으면 보통으로 다니므로 실수로 버그를 넣어 버립니다
그렇다고 해서 매회
NotifyEndpoint.where(platform: NotifyEndpoint.platforms[:gcm])
와 같은 기술 방법을 하는 것은 클래스명 2회 써야 하고, enum의 서수에 대해 일일이 의식하지 않으면 안 되는 것은 귀찮습니다.↑의 문제를 회피하면서, 번거롭지 않은 기법을 할 수 있도록 enum명으로 scope를 살려주는 패치를 썼습니다
lib/active_record/enum/scoping.rb
등에 두고 사용하면 사용할 수 있다고 생각합니다.if defined?(ActiveRecord) && defined?(::ActiveRecord::Enum)
module ActiveRecord
module Enum
module Scoping
def self.extended(base)
::ActiveRecord::Enum.alias_method_chain(:enum, :scoping)
end
end
def enum_with_scoping(definitions)
enum_without_scoping(definitions)
define_scoping_method(definitions)
end
private
def define_scoping_method(definitions)
definitions.each do |name, values|
scoping_method_name = "#{name}_as".to_sym
scope(scoping_method_name, - > (item) { enum_scope(name, item) }})
end
end
end
def enum_scope(enum_name, item_name)
query_hash = {}
query_hash[enum_name.to_sym] = send(enum_name.to_s.pluralize)[item_name]
where(query_hash)
end
end
::ActiveRecord::Base.extend(::ActiveRecord::Enum::Scoping)
end
이것을 도입하면 이하와 같이,
<enum_name>_as
라고 하는 스코프가 정의되므로, 캐릭터 라인·심볼을 건네주어도 동작하게 되었고, 일일이 클래스 메소드로 값을 변환하거나, 스스로 매회 범위를 정의하지 않고 끝내기 endpoints = NotifyEndpoint.platform_as(:gcm)
#=> SELECT * FROM notify_endpoints WHERE platform = 1;
수요가 있으면 gem으로 해봅시다.
htps : // 기주 b. 코 m/라이 ls/라이 ls/bぉb/마s테 r/아 c ゔぇ레코 rd/ぃb/아c ゔぇ_레코 rd/에누 m. rb )
Reference
이 문제에 관하여(ActiveRecord::Enum으로 빠지기 쉬운 실수를 피하십시오), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/ainame/items/a097558e74bf7d5087b9텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)