【问题标题】:Rails / ActiveRecord working with mysql BITRails / ActiveRecord 使用 mysql BIT
【发布时间】:2013-05-07 10:00:47
【问题描述】:

我在使用 Rails 和 ActiveRecord 中的 mysql 位时遇到问题。 我们为 Localities 的已发布状态存储了一些信息。

`published` bit(1) NOT NULL

我在 rails 中将其搭建为 published:binary

Locality.first.published返回"\x01"

如何让 rails 将此字段视为布尔值?

有一个陈旧的票证,但破解 ActiveRecord 并不是一个真正的选择。 https://rails.lighthouseapp.com/projects/8994/tickets/6102-activerecord-boolean-support-with-bit1-mysql-data-type

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3


    【解决方案1】:

    您可以覆盖已发布属性的属性阅读器:

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

    更新

    或者为你的布尔返回值生成一个方法

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

    所以你可以调用:

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

    但我认为第一个解决方案(覆盖属性读取器)更好。

    【讨论】:

    • 我已经考虑过这样做,但似乎不是一个好的解决方案。
    • 为什么不呢?你为什么不使用普通的布尔字段而不是位?
    • 我会使用布尔值而不是位,但我认为它会破坏一些仍在使用的遗留应用程序。我只是希望找到一种方法来绕过与“\x01”的比较,这可能会在未来的某个时候中断。
    • 我明白了。如果您只想解决“\x01”,我认为最简单的方法是覆盖属性读取器。否则,您可能需要更改整个应用程序的大量代码,如果“\x01”有时会更改为普通布尔值..
    【解决方案2】:

    Rails 5 的更新:新的属性 API 是为处理这种情况而设计的。首先你定义一个ActiveRecord::Type::Value 的子类来处理deserializeing 从位到布尔,以及casting 从布尔到位:

    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
    

    然后您使用attribute 帮助器在您的模型上定义属性:

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

    【讨论】:

      【解决方案3】:

      这是基于@Mattherick 上述回答的扩展方法:

      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)
      

      并要求在初始化程序中:

      config/initializers/extensions.rb

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

      然后可以使用:

      class Locality < ActiveRecord::Base
        alias_bit_to_boolean :published
      end
      

      这将产生一个locality.published? 方法。

      【讨论】:

        【解决方案4】:

        感谢您@Mattherick 的帮助。

        在你的帮助下,我构建了一些更简单的东西:

          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
        

        highlight 是在数据库中存储为BIT 的字段的名称。此解决方案也适用于 checkbox 视图,无需更改:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-03
          相关资源
          最近更新 更多