Причина, по которой второй фрагмент не изменяет массив, та же самая, почему этот фрагмент:
def foo(x)
x = [1]
end
a = []
foo(a)
не меняет переменную а. Переменная x в вашем коде является локальной для области видимости блока, и из-за этого вы можете присвоить ей что угодно, но это назначение не будет видно снаружи (Ruby является языком передачи по значению).
Конечно, блоки также имеют замыкания на локальные переменные, в которых они были объявлены, так что это будет работать:
def foo(x)
yield(x)
end
b = []
foo(123) do |x|
b = [1]
end
p b # outputs [1]