-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for ActiveRecord::Enum #9
Comments
Yeah, this is expected behavior. It looks like about this should be written into Readme. |
I think Rails' Or, we could probably even query the enum on class load, so a model would only have: class AddOn < ActiveRecord::Base
pg_enum :category
end |
The code for the AR::Enum is really short, I "forked" it for our application to change a few things:
Could be used as a base here: https://gist.github.com/ioki-klaus/9cc363153cc6ecef649c274aff00a7ad |
I don't know if something like this should be integrated into the project, but here's how I'm making working with the enums a little easier. In my case, I really did need to get the list of candidate values so I could create a GraphQL enum with graphql-ruby. A base class for working with all PostgreSQL enums: class PgEnum
def enum_name
raise NotImplementedError
end
def self.values
ActiveRecord::Base.connection.enums[:integration_account_state]
end
def self.as_activerecord_enum
values.each_with_object({}) { |enum_value, hash| hash[enum_value] = enum_value }
end
end What a specific enum looks like: class IntegrationAccountState < PgEnum
def self.enum_name
:integration_account_state
end
end How a model can use this enum helper: class Sample < ActiveRecord::Base
enum account_state: IntegrationAccountState.as_activerecord_enum, _prefix: :account_state
validates :account_state, :inclusion => { in: IntegrationAccountState.values }
end I've only just begun to use this library, but those little helpers helped improve the aesthetics of the code. I haven't used it long enough to have encountered any pitfalls yet. |
I added these methods to class ApplicationRecord < ActiveRecord::Base
def self.pg_enum_values(attr_name)
metadata = column_for_attribute(attr_name).sql_type_metadata
unless metadata.type == :enum
raise ArgumentError, "Expected `:enum` type for column `#{attr_name}`, but was #{metadata.type}"
end
connection.enums[metadata.sql_type.to_sym]
end
def self.pg_enum(attr_name, options = {})
enum options.merge attr_name => pg_enum_values(attr_name).to_h { |v| [v, v] }
end
end So now my models look like this: class Listing < ApplicationRecord
pg_enum :status
pg_enum :condition, _suffix: true
validates :condition, :inclusion => { in: pg_enum_values(:condition) }
end |
In general, I am very against of having code, that calls database on class load. IMO this might create desync problems with code/db versions of enum. So have come to another idea of doing this w/o interacting with database - via parsing of class ApplicationRecord
def self.pg_enumerize(field, as:, **attrs)
schema = Rails.root.join("db/schema.rb").read
matched = schema.match(/create_enum :#{as}, \[([^\]]*)\]/m)
values = matched[1].tr(" \n\"", "").split(",").map(&:to_sym)
enumerize field, in: values, **attrs
end
end
class SomeModel < ApplicationRecord
pg_enumerize :field, as: :enum_type, ...
end P.S. This is actually for |
When trying to use ActiveRecord's Enum stuff with an enum column I end up with a type mismatch when creating records. ActiveRecord defaults to converting the enum values to integers which does not map correctly to PostgreSQL's enum types. The workaround is to specify each value as the string version of the enum.
Model
Error
Workaround
The text was updated successfully, but these errors were encountered: