I have an enumeration in my model as follows:
enum construction_type: {
brick_block: "Brick/Block",
concrete_slab: "Concrete/Slab",
wood_steel: "Light Framed Wood/Steel",
timber_steel: "Heavy Framed Timber/Steel"
}
In a form, I use this code to grab the values of the enum to put into a dropdown:
<%= form.label(:construction_type, class: "form-label") %>
<% options = options_for_select(Site.construction_types.map {|key, value| [value, Site.construction_types.key(value)]}, form.object.construction_type) %>
<%= form.select(:construction_type, options, include_blank: true) %>
While the statement in options_for_select
seems like overkill when Site.construction_types.values
yields the same options, the field only remains populated after an invalid submit on the form when using the mapped method.
One solution I've found is to hardcode the strings into the form as follows:
<%= form.label(:construction_type, class: "form-label") %>
<%= form.select(:construction_type, ["Brick/Block", "Concrete/Slab", "Light Framed Wood/Steel", "Heavy Framed Timber/Steel"], include_blank: true) %>
However, I would like to avoid this solution as I have a second form used to edit the information initialized in this one where I would have to duplicate the code. An enumeration in the model seems like the best way to keep track of these values.
My database populates as I would like with the values from the enum, but on a page where I am trying to display the information from the form, the keys appear instead.
<li> <strong> <%= t(".construction_type") %> </strong> <%=@site.construction_type if @site.construction_type %> </li>
Using the enumerated version, the code above yields the following: Construction Type: brick_block
As opposed to what I want: Construction Type: Brick/Block
Is there a way to fix this using the enumeration method?
An enumeration in the model seems like the best way to keep track of these values.
Hell no. ActiveRecord::Enum is designed to connect a integer or any other type thats efficient to store and index to a developer readable label.
When you define your enum as:
enum construction_type: {
brick_block: "Brick/Block",
concrete_slab: "Concrete/Slab",
wood_steel: "Light Framed Wood/Steel",
timber_steel: "Heavy Framed Timber/Steel"
}
You're going to be storing "Heavy Framed Timber/Steel"
as the value in the database which is a downright bad idea as you're asking for denormalization issues if you ever need to change the human friendly labels. The enum mapping should not be expected to change.
If you really want to use an Enum then use the I18n module to provide the human readible versions:
# the name is just an assumption
class Building < ApplicationRecord
enum construction_type: {
brick_block: 0,
concrete_slab: 1,
wood_steel: 2,
timber_steel: 3
}
end
module BuildingsHelper
def construction_type_options
Building.construction_types.keys do |key|
[key, t("activerecord.models.buildings.construction_types.#{ key }")]
end
end
end
But a less hacky alternative is to use a seperate table/model:
class Building
belongs_to :construction_type
end
class ConstructionType
has_many :buildings
end
<%= form_with(model: @buildling) do |form| %>
<%= form.collection_select :construction_type_id,
ConstructionType.all,
:id,
:description
%>
<% end %>