일반적으로 전역 변수는 좋지 않습니다. 그러나 때로는 전역이 올바른 위치에 있으면 코드가 훨씬 간단해질 수 있습니다.
Rails에서는 요청 중에 데이터를 한 번 설정할 수 있지만 앱의 모든 계층에서 사용합니다. 어떤 사용자가 요청을 하고 있습니까? 어떤 권한이 있습니까? 어떤 데이터베이스 연결을 사용해야 합니까?
이 정보는 코드 전체에서 사용할 수 있어야 하므로 모든 곳에서 전달하는 것은 많은 잡음이 될 것입니다. 그러나 Ruby 전역 변수를 사용하거나 클래스 변수를 설정하면 자체 문제가 발생합니다. 여러 스레드가 이를 덮어쓸 수 있으며 결국 엄청난 혼란을 일으키고 복구할 수 없을 정도로 잘못된 데이터가 될 수 있습니다.
전 세계적인 것이 필요하지만 당신의 요청을 위한 것입니다. .
일반 Ruby 방식
일반적으로 Thread.current[]
로 처리되는 것을 볼 수 있습니다. . 다음과 같습니다.
Thread.current[:current_user] = user
이것은 충분히 간단합니다. 괜찮은 솔루션입니다. 하지만 두 가지 큰 단점이 있습니다.
-
누군가 실수로 데이터를 덮어쓸 수 있습니다.
두 사람이 같은 키를 골랐다면? 당신은 서로의 데이터를 밟을 것입니다. 사용자와 같은 것을 저장하는 경우 심각하게 나쁠 것입니다. 자신의 앱에서는 아마도 문제가 되지 않을 것입니다. 하지만 gem을 작성 중이거나 Rails 앱이 크고 지저분하다면 한 번 생각해 보아야 합니다.
-
잘 구성되지 않았습니다.
Thread.current[]
데이터의 큰 가방일 뿐입니다. 쉽게 문서화할 수 없습니다. 그것에서 무엇을 꺼낼 수 있는지 알고 싶다면 그 안에 무엇을 넣었는지 검색해야 합니다.물론 이것이 문제가 될 만큼 충분한 전역 데이터를 버린다면
Thread.current[]
보다 더 걱정해야 합니다. 의 구조가 부족합니다. 그러나 여전히 염두에 두어야 할 사항입니다.
그래서 Thread.current[]
보다 더 나은 솔루션이 있습니까? ? 상상할 수 있듯이 Rails 자체는 많은 요청 로컬 데이터를 관리합니다. 그리고 ActiveSupport라는 상품 상자에는 따라야 할 다른 패턴이 있습니다.
레일즈 방식
ActiveSupport를 검색하면 ActiveSupport::PerThreadRegistry
가 실행될 수 있습니다. . 이름에서 이것이 바로 우리가 찾고 있는 것임을 알 수 있습니다.
ActiveSupport::PerThreadRegistry
사용 , 이전 예는 다음과 같습니다.
class RequestRegistry
extend ActiveSupport::PerThreadRegistry
attr_accessor :current_user, :current_permissions
end
RequestRegistry.current_user = user
RequestRegistry.current_user # => user
조금 더 많은 작업입니다. 하지만 ActiveSupport::PerThreadRegistry
를 사용하면 :
-
문서를 보관할 장소가 있습니다. 여러분의 수업을 보는 사람은 누구나 여러분이 기대하는 글로벌 데이터와 그들이 사용할 수 있는 글로벌 데이터를 정확히 알 것입니다.
-
멋진 API를 얻을 수 있습니다. 실제로 클래스 변수를 설정하는 것처럼 보입니다. 스레드에 대해 걱정할 필요가 없다면 아마도 그렇게 했을 것입니다.
-
클래스에 설정한 모든 데이터는 네임스페이스가 지정됩니다.
RequestRegistry.current_user
에 대해 걱정할 필요가 없습니다.PhoneNumberApiRegistry.current_user
와 충돌 , 완전히 별개로 취급됩니다.
Rails는 ActiveSupport::PerThreadRegistry
를 사용합니다. 내부적으로 ActiveRecord 연결 처리, EXPLAIN 쿼리 저장 및 ActiveSupport::Notifications. 따라서 PerThreadRegistry
의 기능에 대한 더 좋은 예를 찾고 있다면 , Rails 자체가 시작하기에 좋은 곳입니다.
스레드와 요청이 일치하지 않는 경우
일부 Rails 서버의 경우 단일 스레드가 여러 요청을 처리합니다. 이것은 PerThreadRegistry
에 넣는 모든 것을 의미합니다. 다음 요청을 위해 머물 것입니다. 이것은 아마도 당신이 원하는 것이 아닐 것입니다.
Rails가 하는 일을 하고 PerThreadRegistry
에 넣은 것을 정리할 수 있습니다. 당신이 그들과 함께 한 후. 거기에 무엇을 넣느냐에 따라 어쨌든 이렇게 할 수 있습니다.
의견에서 MattB는 더 쉬운 솔루션인 request_store를 가리킵니다. Thread.current[]
와 같은 역할을 합니다. , 그러나 각 요청 후에 자체적으로 지워집니다.
이렇게 하면 누군가가 PerRequestRegistry
를 만들 수 있는 문이 활짝 열려 있습니다. , PerThreadRegistry
의 API와 request_store의 안전성을 결합합니다. . 누군가 이미 이 작업을 수행했다면 그 소식을 듣고 싶습니다!
사용해 보기
글로벌 데이터는 나쁠 수 있습니다. 전역 변수가 너무 많으면 빠르게 유지 관리할 수 없는 코드가 생성될 수 있습니다.
하지만 전체 요청에 대해 중앙 위치에 데이터를 보관하는 것이 합리적이라면 Thread.current[]
이상으로 이동하세요. . ActiveSupport::PerThreadRegistry
제공 또는 request_store 샷. 다른 방법이 없다면 글로벌 데이터를 처리하는 것이 조금 덜 위험할 것입니다.