views:

68

answers:

1

I'm wondering if writing functions like this is considered good or bad form.

def test(x)
    if x == 1
        return true
    else
        return "Error: x is not equal to one."
    end
end

And then to use it we do something like this:

result = test(1)

if result != true
    puts result
end

result = test(2)

if result != true
    puts result
end

Which just displays the error message for the second call to test.

I'm considering doing this because in a rails project I'm working on inside my controller code I make calls to a model's instance methods and if something goes wrong I want the model to return the error message to the controller and the controller takes that error message and puts it in the flash and redirects. Kinda like this

def create
    @item = Item.new(params[:item])

    if [email protected]?
        result = @item.save_image(params[:attachment][:file])

        if result != true
            flash[:notice] = result

            redirect_to(new_item_url) and return
        end

        #and so on...

That way I'm not constructing the error messages in the controller, merely passing them along, because I really don't want the controller to be concerned with what the save_image method itself does just whether or not it worked.

It makes sense to me, but I'm curious as to whether or not this is considered a good or bad way of writing methods. Keep in mind I'm asking this in the most general sense pertaining mostly to ruby, it just happens that I'm doing this in a rails project, the actual logic of the controller really isn't my concern.

+5  A: 

I would say that methods that return different types (e.g. boolean vs. string vs. numbers) under different circumstances are a bad practice.

If you have some sort of test method that wants to return details of why the test has not passed then you can return a pair of values (an Array) as follows:

def test(x)
    if x == 1
        return true, "x is fine"
    else
        return false, "Error: x is not equal to one."
    end
end

and then write the section of your controller code as:

valid, message = @item.save_image(params[:attachment][:file])

if !valid
  flash[:notice] = message
  redirect_to(new_item_url) and return
end

If you're talking about a save_image method that will succeed the majority of the time but may fail and you want to indicate this failure and the reason then I would use exceptions e.g.

def save_image(file)
  raise "No file was specified for saving" if file.nil? 
  # carry on trying to save image
end

and then your controller code would be along the lines of:

begin
  result = @item.save_image(params[:attachment][:file])
rescue Exception => ex
  flash[:notice] = ex.message
  redirect_to(new_item_url) and return
end
mikej
That's actually a much better idea. The reason I was even wondering if this was good or bad practice was because different data types could be returned. That's not a huge deal since Ruby is flexible like that, but from the standpoint of clean, understandable, and maintainable code it just bugged me.
seaneshbaugh
I definitely like the exceptions. The first solution i do not like. It is very clean code, but i don't like the fact that a function is also concerned about the error-message which needs to be sent to the user. In a I18n situation this would completely mess up :)
nathanvda