Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails / ActiveRecord working with mysql BIT

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

like image 538
Rene Koller Avatar asked May 07 '13 10:05

Rene Koller


3 Answers

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.

like image 190
Matthias Avatar answered Nov 06 '22 04:11

Matthias


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
like image 34
Josh Justice Avatar answered Nov 06 '22 04:11

Josh Justice


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.

like image 1
cweston Avatar answered Nov 06 '22 05:11

cweston