Ruby on Rails Form Add an "Other" Option with Text Box to Select Dropdown

Viewed 328

I have a ruby form that includes the following code

        <%= form.label(:emitter_type, class: "form-label") %>
        <%= form.select(:emitter_type, BoilerPlant.emitter_type , include_blank: true) %>

        <% if boiler_plant.emitter_type != "Other" %>
        <div id="emitter_other", style="display:none;">
          <% else %>
          <div id="emitter_other">
            <% end %>


          <%= form.label(:emitter_type_other, class: "form-label") %>
          <%= form.text_field(:emitter_type_other , autocomplete: "off", autocapitalize: "on", class: "form-input") %>

          </div>

BoilerPlant.emitter_type Is the following call to a function in my model that produces the array of options I use in my dropdown:

  def self.emitter_type
    ["Baseboard", "Fan Coil", "Heat Pump", "Other"]
  end

I use javascript to make the text field emitter_type_other appear when "Other" is selected. Below is the javascript I use to set the value of my select field to the value I type in the text field (ignore the odd naming conventions).

var toggleRevertValues = document.getElementById("plant_submit_button");
var deleteEmitterType = document.getElementById("boiler_plant_emitter_type");
var deleteEmitterOther = document.getElementById("boiler_plant_emitter_type_other");

toggleRevertValues.addEventListener("click", function(e) { 

 if ( deleteEmitterType.value == "Other" ) {
                deleteEmitterType.value = deleteEmitterOther.value;
            }
}

The dropdown populates with a value if I type in the exact name of one of the options that already exists in my array (such as "Baseboard"). However, if I type in a new option, it shows up as null in the database, and my dropdown comes up as blank on an invalid submit. Is there any way to change my code so it allows a new value for the select?

1 Answers

In order to add a new emitter_type when user selects "Other" and types a new emitter type is to create a couple of new models: EmitterType' and 'BoilerEmitterType. The second is just a join table.

class Boiler < ActiveRecord::Base
  has_many :boiler_emitter_types, dependent: :destroy
  has_many :emitter_types, through: :boiler_emitter_types
end

class BoilerEmitterType < ActiveRecord::Base
  belongs_to :boiler
  belongs_to :emitter_type
end

class EmitterType
  has_many :boiler_emitter_types, dependent: :destroy
  has_many :boilers, through: :boiler_emitter_types
end

Then in response to the form submission, you either assign an existing EmitterType to the Boiler instance, or create a new EmitterType and assign it to the Boiler instance.

ActiveRecord has a nice method that will do this for you:

# boilers_controller.rb
def update
  @boiler = Boiler.find(boiler_params(:id))
  @emitter_type = EmitterType.find_or_create_by(name: boiler_params(:emitter_type_name)
  @boiler.emitter_types << @emitter_type
  if @boiler.save
    # do something
  else
    # do something else
  end
end

private
def boiler_params
# create the 'strong parameters' here
end

note, we're looking for the emitter type by name, not by id, which would be the typical response from a select option.

Related