8

I'm having problems working with a mysql bit in Rails and ActiveRecord. We store a bit for the published-state of Localities.

`published` bit(1) NOT NULL

I scaffolded it as published:binary in rails.

Locality.first.publishedreturns "\x01".

How do I get rails to treat this field as a boolean?

There is a staled Ticket but hacking ActiveRecord is not really an option. https://rails.lighthouseapp.com/projects/8994/tickets/6102-activerecord-boolean-support-with-bit1-mysql-data-type

4 Answers 4

6

You can overwrite the attribute reader of your published attribute:

class Locality < ActiveRecord::Base
  # overwrite the attribute reader of the published attribute
  def published
    self.read_attribute(:published) == "\x01" ? true : false 
  end
end

UPDATE

Or generate a method for your boolean return value

class Locality < ActiveRecord::Base
  def to_boolean
    self.published == "\x01" ? true : false
  end
end

So you can call:

 Locality.first.published.to_boolean => true || false

But I think the first solution (overwriting attribute reader) is better.

Sign up to request clarification or add additional context in comments.

4 Comments

I have already thought about doing it that way, but it does not seem like a good solution.
and why not? why are you not using a normal boolean field instead of the bit?
I would have used a boolean instead of a bit but I think it would break some legacy applications that are still in use. I just hoped to find a way around the comparison with "\x01" which could break sometime in the future.
well I understand. If you only want to work around the "\x01" I think the easiest way is to overwrite the attribute reader. Otherwise you´ll maybe have to change a lot of code overall your application, if the "\x01" will change to a normal boolean sometimes..
4

Update for Rails 5: the new attributes API is made for handling situations just like this. First you define a subclass of ActiveRecord::Type::Value that handles deserializeing from bit to boolean, and casting back from boolean to bit:

module Values
  class BitBoolean < ActiveRecord::Type::Value
    BIT_FALSE = "\x00"
    BIT_TRUE = "\x01"

    def cast(value)
      value ? BIT_TRUE : BIT_FALSE
    end

    def deserialize(value)
      value == BIT_TRUE
    end
  end
end

Then you define the attribute on your model with the attribute helper:

class MyModel < ApplicationRecord
  attribute :published, Values::BitBoolean.new
end

Comments

1

Heres an extension method based on @Mattherick's answer above:

lib/extensions/active_record/bit_boolean.rb

module Extensions::ActiveRecord
  module BitBoolean
    extend ActiveSupport::Concern

    class_methods do
      def alias_bit_to_boolean(attribute)
        define_method("#{attribute}?") do
          self.send(attribute) == "\x01" ? true : false
        end
      end
    end

  end
end

ActiveRecord::Base.send(:include, Extensions::ActiveRecord::BitBoolean)

and require in an initializer:

config/initializers/extensions.rb

require File.join(Rails.root, 'lib/extensions/active_record/bit_boolean.rb')

Which then can be used:

class Locality < ActiveRecord::Base
  alias_bit_to_boolean :published
end

This will produce a locality.published? method.

Comments

1

Thank you for your help @Mattherick.

With your help I have built something easier:

  def highlight
    self.read_attribute(:highlight) == "\x01" ? true : false
  end

  def highlight=(value)
    content_value = (value == false || value == 0 || value == "0") ? "\x00" : "\x01"
    self.write_attribute(:highlight,content_value)
  end

The highlight is the name of the field stored as BIT on database. And this solution also works with checkbox on view without the need of changes:

  <div class="field">
    <%= f.label :highlight %>
    <%= f.check_box :highlight %>
  </div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.