我正在尝试将ActiveRecord对象中的MySQL时间戳转换为另一种时间戳格式。我的方法获取一个ActiveRecord记录数组,并返回带有带时间戳字段的哈希数组,格式为时间戳:
def convert_mysql_timestamps(records)
ary = []
hash = {}
records.each_with_index do |record, i|
record.attributes.each do |field, value|
if time_columns.include?(field) and value then
hash[field] = value.strftime("%Y-%m-%dT%H:%M:%S%z")
else
hash[field] = value
end
end
ary[i] = {}
ary[i] = hash
end
ary
end
但是,在ary[i] = hash
分配中,所有ary
元素都设置为哈希值。
有没有更好的方法来转换记录的时间戳字段? (我不需要将记录保存回数据库。)另外,如何让数组捕获记录的每个哈希表示?
输入:
[#<Vehicle id: 15001, approved_at: "2011-03-28 10:16:31", entry_date: "2011-03-28 10:16:31">, #<Vehicle id: 15002, approved_at: "2011-03-28 10:16:31", entry_date: "2011-03-28 10:16:31">]
期望的输出:
[{"id"=>15001, "approved_at"=>"2011-03-28T10:16:31-0700", "entry_date"=>"2011-03-28T10:16:31-0700"}, {"id"=>15002, "approved_at"=>"2011-03-28T10:16:31-0700", "entry_date"=>"2011-03-28T10:16:31-0700"}]
答案 0 :(得分:1)
问题是你正在创建一个哈希:
def convert_mysql_timestamps(records)
ary = []
hash = {}
#...
然后尝试重复使用每条记录。您可能希望每次each_with_index
迭代都有一个新的Hash:
def convert_mysql_timestamps(records)
ary = []
records.each_with_index do |record, i|
hash = { }
record.attributes.each do |field, value|
#...
end
ary[i] = hash
end
end
答案 1 :(得分:0)
您可以使用map
- 当您想要以一种格式获取数组并在另一种格式中生成相同大小的数组时,它总是一个不错的选择。方法如下:
def convert_mysql_timestamps(records)
records.map do |record|
Hash[records.attributes.map{|k, v| [k, convert_mysql_timestamp(v)] }]
end
end
def convert_mysql_timestamp(field, value)
return value unless time_columns.include?(field) && value
value.strftime("%Y-%m-%dT%H:%M:%S%z")
end
它的工作原理如下:
Hash[array_of_pairs]
将一组键值对(如[["foo", 2], ["bar", 3], ...]
)转换为类似{"foo" => 2, "bar" => 3, ...}
的哈希值。
map
为集合中的每个项调用其块,并将块的每个返回值收集到它返回的新数组中。 attributes.map
内的Hash[...]
创建了键值对数组,外部records.map
将所有哈希值收集到返回的数组中。
我建议您阅读Enumerable中的方法,因为那里有很多像map
这样的简洁内容。你会发现你几乎从来没有必要在你的循环中使用索引,尽管如果你来自另一种语言,其中for
循环到处都是一个很难打破的习惯!
答案 2 :(得分:0)
我不确定您的time_columns
是什么,但假设它们是Time
类,您可以像value.is_a?(Time)
那样简化部分。
def convert_mysql_timestamps(records)
records.collect do |record|
# assuming records are from a Rails model, I am using #attributes
# to loop through all fields in a record
# then inject values in this hash -> ({}),
# which is in the block, named attributes
record.attributes.inject({}) do |attributes, (column_name, value)|
# if it is Time, convert it to iso8601 (slightly different from your format,
# but if this is also acceptable, your code can be simpler)
attributes[column_name] = (value.is_a?(Time) ? value.iso8601 : value)
attributes
end
end
end