提问人:Qd1y 提问时间:10/23/2023 更新时间:10/23/2023 访问量:40
Ruby on Rails 似乎破坏了方法中的常量
Ruby on Rails seems to corrupt a constant in a method
问:
我的常量似乎被修改了,但它怎么可能。
环境是 Rails 7.0.7.2 Ruby 3.1.2p20 通过 rbenv
考虑
module ArrayTestMethods
PROFILE_PARAMS = [["id","id"],["customer_id","contactId"],["channelId","channelId"],["identifierId","identifierId"],["platform","platform"],["identifier","identifier"],["created","createdAt"],["updated","updatedAt"]].freeze
def showme
params = {"id"=>"d1", "contactId"=>"contact1", "channelId"=>"bbc2", "identifierId"=>"ident2", "platform"=>"events", "inheritedFrom"=>"", "createdAt"=>"2023-10-19T17:03:58Z", "updatedAt"=>"2023-10-19T17:03:58Z", "identifier"=>"353860872561"}
x = model_from_hash(params, PROFILE_PARAMS)
pp x
end
def json_walker(params, *args)
args.each do | arg|
params = params[arg]
return nil if params.nil?
end
return params
end
def model_from_hash(params, array_map, debug = false)
#im doing the below as a test i've tried
# array = array_map.clone same result
# i've also tried using array_map on its own
array = Array.new
array << array_map
attributes_array = array[0]
puts "array map before"
pp attributes_array
attr_hash = Hash.new
attributes_array.each do | arr|
model_attribute = arr[0]
arr.shift
data = json_walker(params, *arr)
puts "arr0 - #{model_attribute} data - #{data}" if debug
end
puts "array map after "
pp array_map
return array_map
end
module_function :json_walker, :model_from_hash, :showme
答:
2赞
spickermann
10/23/2023
#1
arr.shift
修改数组。
因此,您可以在不修改原始数组的情况下将值从一个变量传递到另一个变量,而不是修改块中的数组。each
我会尝试改变
attributes_array.each do | arr|
model_attribute = arr[0]
arr.shift
data = json_walker(params, *arr)
puts "arr0 - #{model_attribute} data - #{data}" if debug
end
自
attributes_array.each do | arr|
model_attribute = arr[0] # first element
data = json_walker(params, arr[1..-1]) # elements from second position to the end
puts "arr0 - #{model_attribute} data - #{data}" if debug
end
1赞
max
10/23/2023
#2
首先,你似乎对 Ruby 抱有不切实际的期望。它不会深度冻结包含在另一个对象中的对象。例如:.freeze
[1, 2, 3].freeze.push(0) # can't modify frozen Array: [1, 2, 3] (FrozenError)
[[1, 2, 3]].freeze.tap {|x| x[0].push(4)} == [[1, 2, 3, 4]] # true
这不是数据被“损坏”。这就是语言的工作方式,Rails 并没有改变 Ruby 的基本原理。
如果您要做的是规范化一组输入参数或生成序列化输出,那么有更好的方法可以做到这一点。
您可以简单地创建一个 Hash,其中包含输入键和规范化形式的映射:
MAPPING = {
"contactId" => "customer_id"
"createdAt" => "created"
"updatedAt" => "updated"
}.freeze
然后,您只需转换哈希的键:
params.transform_keys(MAPPING)
{"id"=>"d1",
"customer_id"=>"contact1",
"channelId"=>"bbc2",
"identifierId"=>"ident2",
"platform"=>"events",
"inheritedFrom"=>"",
"created"=>"2023-10-19T17:03:58Z",
"updated"=>"2023-10-19T17:03:58Z",
"identifier"=>"353860872561"}
如果作业更复杂,请创建一个具有属性的对象(类),并在 setter、initializer 或工厂方法中处理转换。
class ThingAdapter
attribute_accessor :customer_id
alias_method :contactId=, :customer_id=
def initialize(**params)
params.each do |k,v|
self.send("#{k}=", v)
end
end
end
一般来说,在 Rails 中,每当你进行任何繁重的数组或哈希操作时,你几乎肯定做错了。
评论
0赞
max
10/24/2023
是的,Ruby 中的常量并不意味着不可变。这只是意味着,如果你尝试重新分配 Ruby,它会抱怨一点。
0赞
Qd1y
10/24/2023
谢谢大家。对不起,我把问题复杂化了。在控制台中,定义一个常量,然后PARAMS.object_id给出 497700。然后如果我说y.object_id给出 528900。如果我现在执行'y[0].shift,我得到[[1],[1,1]]。然后,如果我将 PARAMS 放在控制台中,即使它们是两个不同的对象,我也会得到与 y 相同的结果。- 我错过了什么PARAMS=[[0,0],[1,1]]
y = PARAMS.clone
0赞
max
10/24/2023
这是因为它不是深度克隆。数组内部的数组是对原始对象的引用。.请参阅 makandracards.com/makandra/...x = ARY.clone; x[0].object_id == ARY[0].object_id;
0赞
max
10/24/2023
同样,对数组实际上并不是您通常应该使用的数据类型。我会放弃这个尝试,花一些时间实际学习如何在 Ruby 中使用哈希值以及 Enumerable 提供的方法。你基本上用一些非常糟糕的代码把自己画到了一个角落里,你并没有真正去尝试修复它。
评论
.freeze