Rails Hash to Struct - 원숭이 패치
serialize :settings, ActiveSupport::HashWithIndifferentAccess
. Rails 7.0.4는 그것을 망쳤습니다. 나는 해시 대 '문자열'에서 기호를 사용하는 것을 좋아하기 때문에 HashWithIndifferentAccess를 사용하고 있었습니다. Rails는 YAML을 사용하여 해시를 직렬화합니다. YAML에는 보안 버그가 있었고 Rails는 직렬화할 항목을 명시적으로 정의하도록 요구하여 이를 수정했습니다. 문제를 해결하는 데 약간의 시간이 걸렸지만 버그에 대한 이야기에서 그들은 기본적으로 'JSON을 사용하지 않는 이유'라고 말했습니다.제가 리팩토링한 내용 중 일부입니다. 나는 여전히 HashWithIndifferentAccess에서 JSON으로 몇 가지 속성을 변경하는 방법을 알아 내려고 노력하고 있습니다. 다음과 같을 것 같습니다.
serialize :settings, ActiveSupport::HashWithIndifferentAccess
serialize :settings, JSON
를 추가하고 재배포합니다. 아마 15분 정도 걸릴 것 같지만 조금 더 생각해 보고 싶습니다.
내가 최근에 하고 있는 것은 이러한 설정/기본 설정 해시 중 일부를 Struct(원래 OpenStruct - 그러나 포기함)로 변환하는 것입니다. 다시 말하지만 이것은 개인적인 취향일 뿐입니다. 저는
settings.acct_placeholders
보다 settings['acct_placeholders']
를 선호합니다. 저는 원래 config/initializers에 있는 Monkey Patch를 사용하여 이 작업을 수행했습니다.Hash.class_eval do
def to_struct
Struct.new(*keys.map(&:to_sym)).new(*values)
end
end
아마도 좋은 생각은 아니지만 단순 해시에는 작동했지만 중첩된 해시에는 작동하지 않았습니다. Monkey patching in Rails 및 3 Ways to Monkey-Patch Without Making a Mess 에서 Monkey Patching에 대해 조금 더 읽으면서 모듈을 사용하여 Rails 방식으로 수행하기로 결정했습니다.
/lib
core_extensions
에 폴더 하나와 두 개의 하위 폴더hash
및 array
를 추가했습니다. 하위 폴더에서 내 원숭이 패치를 추가했습니다.방금 개념 증명으로 어레이를 추가했습니다.
# just a proof of concept
module CoreExtensions
module Array
def test_array
puts "test_array"
self
end
end
end
이러한 패치가 작동하려면 패치를 로드해야 하므로 config/initializers에서 추가했습니다
monkey_patches.rb
.# config/initializers/money_patches.rb
# Require all Ruby files in the core_extensions directory by class
Dir[Rails.root.join('lib', 'core_extensions/*', '*.rb')].each { |f| require f }
# Apply the monkey patches
Array.include CoreExtensions::Array
Hash.include CoreExtensions::Hash
hash.to_struct
패치의 경우 .to_struct 및 .as_struct라는 두 개의 패치로 끝났습니다. 이것은 스핀오프와 Rails .to_json 및 .as_json입니다. 하나(.as_json)는 해시를 삭제하고 다른 하나는 변환을 수행합니다.# /lib/core_extensins/as_struct.rb
# convert Hash to Struct on a single level
module CoreExtensions
module Hash
def as_struct
Struct.new(*keys.map(&:to_sym)).new(*values)
end
end
end
# /lib/core_extensins/to_struct.rb
# convert Hash to a nested Struct
module CoreExtensions
module Hash
def to_struct
hash_to_struct(self)
end
private
def hash_to_struct(ahash)
struct = ahash.as_struct # convert to struct
struct.members.each do |m|
if struct[m].is_a? Hash
struct[m] = hash_to_struct(struct[m]) # nested hash, recursive call
elsif struct[m].is_a? Array
# look for hashes in an array and convert to struct
struct[m].each_index do |i|
# normal use, an array of hashes
struct[m][i] = hash_to_struct(struct[m][i]) if struct[m][i].is_a? Hash
# convoluded use, an array that may contain hash(es)
struct[m][i] = hash_in_array(struct[m][i]) if struct[m][i].is_a? Array
end
end
end
struct
end
def hash_in_array(arr)
arr.each_index do |ii|
arr[ii] = hash_to_struct(arr[ii]) if arr[ii].is_a? Hash
end
arr
end
end
end
따라서 복잡한 중첩 해시를 정의하면(이 작업을 수행하지 않을 것입니다... 다시 개념 증명)
h = {
game:{id:1,date:'2022-09-11',player:6},
players:[{name:'Joe',quota:21},{name:'Harry',quota:26},{name:'Pete',quota:14},
{name:'don',quota:21},{name:'sally',quota:26},{name:'red',quota:14}],
teams:[['joe','don',team:{a:1,b:2,c:3}],['harry','sally',lost:{skins:2,par3:9}],['pete','red']]}
s = h.to_struct
를 호출하면 복잡한 Struct가 생성됩니다.<struct
game=<struct id=1, date="2022-09-11", player=6>,
players=
[<struct name="Joe", quota=21>,
<struct name="Harry", quota=26>,
<struct name="Pete", quota=14>,
<struct name="don", quota=21>,
<struct name="sally", quota=26>,
<struct name="red", quota=14>],
teams=
[["joe", "don", <struct team=<struct a=1, b=2, c=3>>],
["harry", "sally", <struct lost=<struct skins=2, par3=9>>],
["pete", "red"]]>
그래서
# s.game returns
<struct id=1, date="2022-09-11", player=6>
# s.game.date return
"2022-09-11"
그것은 그!
다시 말하지만, 저는 그저 취미 생활을 하는 사람이고 제 Ruby 기술은 깊지는 않지만 12년 전에 알고 있던 것보다 훨씬 낫습니다.
다른하실 말씀 있나요?
Reference
이 문제에 관하여(Rails Hash to Struct - 원숭이 패치), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/salex/rails-hash-to-struct-a-monkey-patch-pf8텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)