Forum: Ruby on Rails Enum patch for Rails

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Andrey T. (Guest)
on 2006-02-05 12:14
Hello!

I've modified ActiveRecord a bit to support enum columns. This is tested
only with MySQL, and maybe needs some changes for other adapters (if
they use another syntax or quoting style).

I believe this patch should be tested well, so I haven't (yet) tried to
post it to the official Trac. It is also not solid-as-a-rock when it
comes to quoting ENUM values.

After applying this thing, rake db_schema_dump properly handles enum
columns, and also it's possible to write migrations like this:

add_column :users, :level, :enum, :limit => ['viewer', 'author',
'admin']

Observe that I'm (over)using the limit field to specify ENUM values.

Here's the patch.

Index:
activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
===================================================================
---
activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
(revision 3486)
+++
activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
(working copy)
@@ -235,7 +235,15 @@

       def type_to_sql(type, limit = nil) #:nodoc:
         native = native_database_types[type]
-        limit ||= native[:limit]
+        # this is a special case, because data type differs
+        case type
+          when :enum
+            fail ":enum column limit must be specified" if limit.nil?
+            fail ":enum column limit must be an array" unless
limit.is_a? Array
+            limit = limit.collect {|n| "'#{n}'"}.join ","
+          else
+            limit ||= native[:limit]
+        end
         column_type_sql = native[:name]
         column_type_sql << "(#{limit})" if limit
         column_type_sql
Index:
activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
===================================================================
---
activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
(revision 3486)
+++
activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
(working copy)
@@ -18,7 +18,7 @@
         @sql_type = sql_type
         # have to do this one separately because type_cast depends on
#type
         @default = type_cast(default)
-        @limit   = extract_limit(sql_type) unless sql_type.nil?
+        @limit   = extract_limit_or_enum_values(sql_type) unless
sql_type.nil?
         @primary = nil
         @text    = [:string, :text].include? @type
         @number  = [:float, :integer].include? @type
@@ -44,6 +44,7 @@
           when :text, :string then String
           when :binary        then String
           when :boolean       then Object
+          when :enum          then Symbol
         end
       end

@@ -61,6 +62,7 @@
           when :date      then self.class.string_to_date(value)
           when :binary    then self.class.binary_to_string(value)
           when :boolean   then self.class.value_to_boolean(value)
+          when :enum      then value.intern
           else value
         end
       end
@@ -77,6 +79,7 @@
           when :date      then
"#{self.class.name}.string_to_date(#{var_name})"
           when :binary    then
"#{self.class.name}.binary_to_string(#{var_name})"
           when :boolean   then
"#{self.class.name}.value_to_boolean(#{var_name})"
+          when :enum      then "#{var_name}.to_s.intern"
           else nil
         end
       end
@@ -135,6 +138,26 @@
           $1.to_i if sql_type =~ /\((.*)\)/
         end

+        def extract_enum_values(sql_type)
+          paren_string = $1 if sql_type =~ /\((.*)\)/
+          return [] if paren_string.nil?
+          values = []
+          paren_string.split(",").each do |item|
+            item.strip!
+            item = item[1..-2] if item[0] == ?' && item[-1] == ?'  #
remove quoting
+            values << item
+          end
+          values
+        end
+
+        def extract_limit_or_enum_values(sql_type)
+          if type == :enum
+            extract_enum_values(sql_type)
+          else
+            extract_limit(sql_type)
+          end
+        end
+
         def simplified_type(field_type)
           case field_type
             when /int/i
@@ -157,6 +180,8 @@
               :string
             when /boolean/i
               :boolean
+            when /enum/i
+              :enum
           end
         end
     end
Index:
activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
===================================================================
--- activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
(revision 3486)
+++ activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
(working copy)
@@ -107,7 +107,8 @@
           :time        => { :name => "time" },
           :date        => { :name => "date" },
           :binary      => { :name => "blob" },
-          :boolean     => { :name => "tinyint", :limit => 1 }
+          :boolean     => { :name => "tinyint", :limit => 1 },
+          :enum        => { :name => "enum", :limit => [] }
         }
       end
This topic is locked and can not be replied to.