I'm building my first Rails app and I'm running into this weird problem. I'm using Postgres, which supports the ENUM type that is very useful for me. Rails doesn't support this, however, so I'm using many "executes" in my migrations. They all run successfully and seem to work. My database is just the way I want when I examine it through pgAdmin. I'm using 3 ENUM types in the users table at the moment:
gender ('female', 'male')
interested_in ('men', 'women', 'men_and_women')
relationship_status ('single', ..., 'divorced')
For the application side I'm using the classy_enum gem. Then I tried updating the user profile to check if everything was working. At first I erased the interested_in from the edit profile form because it had some different logic for it. Everything worked fine. Then I added interested_in, updated the logic for the new type, and submitted the form again. I got this error:
PG::InvalidTextRepresentation: ERROR: invalid input value for enum interested_in: "0" :
UPDATE "users" SET "interested_in" = $1, "remember_token" = $2, "updated_at" = $3 WHERE "users"."id" = 1
It's trying to save 0 to an enum field that doesn't include this option and then it obviously fails. So, the first time I saw a similar error I thought "where on earth is this 0 coming from??" but it turned out Rails was converting the value to an integer before saving it, and whenever you convert a string with non-numeric characters the result is 0. That's what I suppose is happening again. So I went to the console and typed:
2.0.0p247 :001 > User.columns_hash['interested_in'].type
=> :integer
When I run the same command for gender and relationship_status I get nil, which makes sense cause Rails doesn't understand the ENUM type:
2.0.0p247 :007 > User.columns_hash['gender'].type
=> nil
In pgAdmin I have:

and

respectively.
I've tried restarting my webserver (Pow), the postgres server, but the types still don't match. How can this be possible? How do the Rails database adapters work? What can I do to resolve this messed up situation?
Well, I'm answering my own question but I won't accept it yet, because I still hope for someone with more experience to shed some light on this problem.
I had a hunch it had something to do with the name interested_in, which starts with "int". I then changed the name to is_interested_in but no luck, so I gave up on the hypothesis. After spending some hours puzzled by the problem, dropping my whole database, migrating it again, dropping again, loading it from structure.sql all with no success, I decided to give it a shot again and changed the name of the type to user_interested_in (because that doesn't even start with "i"). Again, no luck. More hours passed by and since I couldn't find anything online or come up with any other hypothesis, I checked carefully the names of the other enum types and saw that they didn't include "int" at all in any position of the string. I then changed the type name from interested_in to attracted_to and guess what? It worked.
User.columns_hash['interested_in'].type
=> nil
My guess is that there's a bug in Rails. It seems like it tries to be smart and guess the column type with some logic like:
model_column_type = :integer if db_column_type.include?("int")
But that's kinda crazy. Why doesn't it check for a full match? Doesn't make any sense to me.
EDIT
Well, that's it. Just checked Rails source and that's exactly what it does:
# rails / activerecord / lib / active_record / connection_adapters / column.rb
require 'set'
module ActiveRecord
# :stopdoc:
module ConnectionAdapters
# An abstract definition of a column in a table.
class Column
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON'].to_set
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set
...
def simplified_type(field_type)
case field_type
when /int/i
:integer
when /float|double/i
:float
.
.
.
when /boolean/i
:boolean
end
end
end
end
That's a serious problem for databases that support the creation of types. Does the regex really have to be so inclusive? Makes me wonder if I should create an issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With