There's a number of patterns in programming, and Ruby in particular, that you'll see time and time again. This generate-and-verify-on-fail-redo type pattern is fairly common, and common enough Ruby has a begin ... end while (cond) structure for it.
One thing that's working against you here is having three variables. This violates the Zero, One or Infinity Rule which is essential to having organized code. When dealing with more than "one" thing, consider using a data structure like an array.
Taking all that into account here's a simple approach:
def random_values(count = 3)
begin
values = Array.new(count) { rand(1...9) }
end while (values.inject(&:-) <= 0)
values
end
This keeps generating lists until you find one that meets your criteria. The inject call is a quick way of performing the subtraction on the numbers in a particular set by iterating through the list and subtracting one element from the next, then using that result in the subsequent loop.
The Array constructor is given two arguments, one is the number of elements to pre-allocate to it, the second is a block that defines how those elements should be produced. This is a quick way of making a N length array of random values.
Now a slightly more Ruby way of doing this is to define a generator of random number sets:
random_values = Enumerator.new do |y|
loop do
y << Array.new(3) { rand(1...9) }
end
end
This allows you to apply the Enumerable library to the problem and find the first entry matching your criteria. Here you can expand the variables in the array within this local test block to keep the code simple:
first = random_values.find do |x, y, z|
x - y - z > 0
end
The advantage of this approach is you can chain things together and get things like this:
selection = random_values.lazy.select do |x, y, z|
x - y - z > 0
end.first(10)
This will "lazy" enumerate arrays, that is it will produce them on-demand instead if running that loop until completion, and will pull out the first 10 that match and save those in an array called selection.