that static method util_name is needed to prevent nil when I need an empty string if it's nil.
def self.util_name(value)
return '' if value.nil?
value.name
end
Okay, given that bit of context you can remove the Budget::util_name method entirely because it isn't doing anything useful. There are two ways of conditionally calling a method on an object that might be nil, one provided by the framework and one by the language.
If you are using Ruby 2.2 or earlier, use the try method.
value.try(:name)
if you are using Ruby 2.3 or above, you can use the safe navigation operator
value&.name
In either case, you don't need to specifically test for nil because it will be automatically coerced into an empty string when interpolated.
"#{envelope_quantity&.name} - envelope #{envelope_size&.name} #{envelope_paper&.name} #{envelope_color&.name} #{envelope_grammage&.name} #{envelope_model&.name} #{envelope_print&.name}"
That's much more reasonable, still probably a bit too long. You could use string templates:
"%{quantity} - envelope %{size} %{paper} %{color} %{grammage} %{model} %{print}" % {
quantity: envelope_quantity&.name,
size: envelope_size&.name,
paper: envelope_paper&.name,
color: envelope_color&.name,
grammage: envelope_grammage&.name,
model: envelope_model&.name,
print: envelope_print&.name
}
But I want to focus on something I noticed about this code sample. Every single method begins with envelope which probably means that these methods are telling you they should be a separate object. If you extract this data into a value object, then the natural location for this helper method becomes obvious...
class Envelope < Struct.new(:quantity, :size, :paper, :color, :grammage, :model, :print)
def to_s
"#{quantity&.name} - envelope #{size&.name} #{paper&.name} #{color&.name} #{grammage&.name} #{model&.name} #{print&.name}"
end
end
Undoubtedly the real code would be more complicated than that, just food for thought.