Compare checkbox with boolean

Hi!

I have a form with a checkbox called “status” which is a boolean in the database.

In my controller’s update action I want to check if the checkbox has changed. Something like this:

if @item.status != params[:item][:status] params[:item][:position] = nil

end

But this doesn’t work as the params[:item][:status] is “0” (an int as a string)

And the @item.status is false/true (a bool)

I have tried to use the .to_i on the status param to make it into an int, but it still doesn’t work. I guess there is no .to_bool? :slight_smile:

So, how do I do this comparison? I’m new to Rails and these small things makes be a bit puzzled :slight_smile:

Tried to use .to_i on the both?

Yes, it gives me this error:

NoMethodError (undefined method `to_i’ for false:FalseClass):

Try @item.status != !params[:item][:status].to_i.zero?

Yes, ended up doing this: !@item.status != params[:item][:status].to_i.zero?

But it looks very ugly to me…

after update do

if @item.status_changed? ...

Hmm, that seems to always return false over here.

I tried this: update_was_successful = @item.update_attributes(params[:item]) puts @item.status_changed?

Which outputs false, always. The weird thing is that it prints that before the update is shown in the console. I guess that is why it’s always false.

Isn’t the update_attributes method updating the item right away?

Since the params will give you either "0" or "1" as a string, and since you are trying to equate "0" (string) to "false" (boolean), why not set a variable equal to "true" or "false" based on the params? Try:

if params[:item][:status] == "0"   bool = false else   bool = true end

or,

bool = (params[:item][:status] != "0")

You can then compare bool to your boolean.

Yes, but that doesn’t look very good either. Not much better than doing this I’m afraid:

!@item.status != params[:item][:status].to_i.zero?

Or put something like this in an initializer:

Or this may be helpful:

def convert_to_boolean(value)   return [true, "true", 1, "1", "T", "t"].include?(value.class == String ? value.downcase : value) end

No, you really shouldn't be doing that in the controller. You almost certainly want to do this in a before_save (or possibly before_validation) callback on the MODEL.

Several reasons:

- it's a best practice to keep business logic in the model ("fat model / skinny controller")

- inside the model callbacks, you've got access to both typecast data (the incoming status will already have the right type) and the _changed? predicate. For instance, your code could be shortened to:

class Item < ActiveRecord::Base

  before_save :update_position

  def update_position     self.position = nil if status_changed?   end

end

Not only does it avoid the messy conversion, it (IMHO) is far more readable.

--Matt Jones

That is very true. Thank you for that!

I ended up changing the behavior though, so I didn’t need to check if the status had changed at all.

Best Regards

Linus