This is an answer to the OP's original question. I have no interest in changing it to attempt to answer a moving target.
Code
def doit(rides)
{ rides: rides.slice_before { |k,_| k.to_s.match? /\Aride\d*\z/ }.
map { |a| hashify(a.flatten.drop(1)) }.
reduce(&:merge) }
end
def hashify(arr)
f,*rest = arr
return f if rest.empty?
{ f.to_sym=>hashify(rest) }
end
Examples
Here is an example of the use of the (recursive) helper method hashify:
hashify ["lyft", :type, "car"]
#=> {:lyft=>{:type=>"car"}}
We are given the hash rides:
rides = {:ride1=>"lyft", :type=>"car", :ride2=>"Scoot",
:type2=>"scooter", :ride3=>"blade", :type3=>"helicopter"}
doit rides
#=> {:rides=>{:lyft=>{:type=>"car"},
# :Scoot=>{:type2=>"scooter"},
# :blade=>{:type3=>"helicopter"}}}
Let's add some more key-value pairs to rides:
rides = {:ride1=>"lyft", :type=>"car", :color=>"blue",
:ride2=>"Scoot", :type2=>"scooter", :make=>"Vespa", :model=>"98",
:ride3=>"blade", :type3=>"helicopter"}
doit rides
#=> {:rides=>{:lyft=>{:type=>{:car=>{:color=>"blue"}}},
# :Scoot=>{:type2=>{:scooter=>{:make=>
# {:Vespa=>{:model=>"98"}}}}},
# :blade=>{:type3=>"helicopter"}}}
Explanation
The steps for the first example are as follows.
enum = rides.slice_before { |k,_| k.to_s.match? /\Aride\d*\z/ }
#=> #<Enumerator: #<Enumerator::Generator:0x00005a49d68217f0>:each>
We can see the elements that will be generated by this enumerator by converting it to an array.
enum.to_a
#=> [[[:ride1, "lyft"], [:type, "car"]],
# [[:ride2, "Scoot"], [:type2, "scooter"]],
# [[:ride3, "blade"], [:type3, "helicopter"]]]
Continuing,
a = enum.map { |a| hashify(a.flatten.drop(1)) }
#=> [{:lyft=>{:type=>"car"}},
# {:Scoot=>{:type2=>"scooter"}},
# {:blade=>{:type3=>"helicopter"}}]
h = a.reduce(&:merge)
#=> {:lyft=>{:type=>"car"}, :Scoot=>{:type2=>"scooter"},
# :blade=>{:type3=>"helicopter"}}
{ rides: h }
#=> <as above>
temp_rides["rides"].merge({"key" => "value"})?rideN, but not very consistently.typevs.type2for instance.undefined method `merge'