ruby-on-railsrubysimple-formcollection-select

Convert a options_for_select to simple_form that uses two collections


This is my first question, so any tips on making it easier for my fellow programmers, I would appreciate it.

Background On a form for placing a photo ad order, you can select a make and a model, but a full list of every model is listed (bad user experience). The code for the form that lists every model is below.

 <div id="photo-ad-make-model-fields" class='make-model-year-selector'>
      <%= f.input :listing_known_make, label: 'Make',
                  collection: vehicle_selection.make_choices,
                  input_html: {
                      id: 'photo-ad-order-form-listing-known-make',
                      class: 'vehicle-make form-control select2 jcf-ignore',
                      data: {
                          target: 'photo-ad-order-form-listing-known-model',
                          placeholder: 'Select a make'
                      }
                  } %>
      <%= f.input :listing_known_model, label: 'Model',
                  collection: vehicle_selection.all_model_choices,
                  input_html: {
                      id: 'photo-ad-order-form-listing-known-model',
                      class: 'vehicle-model form-control select2 jcf-ignore',
                      data: {
                          placeholder: 'Select a model'
                      }
                  } %>

There is a partial used for users to search make or model listings, it works exactly how I want it to work. a user selects a make, clicks on the input for the model, and only make specific models are listed. Code below

<fieldset class="make-model-selector"> <div class="form-group clearfix"> <%= select_tag :make, options_for_select(vehicle_selection.make_choices, vehicle_selection.make), include_blank: true, class: 'vehicle-make form-control select2 jcf-ignore', data: { target: 'model', placeholder: 'Any Make' } %> </div> <div class="form-group clearfix"> <%= select_tag :model, options_for_select(vehicle_selection.model_choices, vehicle_selection.model), include_blank: true, class: 'vehicle-model form-control select2 jcf-ignore', data: { placeholder: 'Any Model' } %> </div> </fieldset> This is driven by java script, that is rails model specific, and is located in the view directory under each models view folder. (first time dealing with js outside the application.js, this is legacy code written by another company). From research I determined that this is a rails feature, and when using rails syntax in javascript it will fail in the application.js file but specifically at the path the models folder in the view, it will fire. (please correct me or let me know anymore about this rails feature that I was unaware of)

Location of index.js files for both make and model in app heirarchy

Code inside view/make/index.js

$('#<%= @target %>') .html('<%=j options_for_select(@makes) %>') .data('placeholder', 'Select a Make');

Code inside view/model/index.js

$('#<%= @target %>') .html('<%=j options_for_select(@models) %>') .data('placeholder', 'Select a Model');

So getting to my problem, the photo ad form is part of a simple_form_for builder. So I know I need to convert the partial code to simple form and include local form variable to be apart of the form object with saving to the database.

My simple_form converted version of the partial, in its own partial called _make_select.erb

  <fieldset class="make-model-selector">
      <div class="form-group clearfix">
          <%= f.input :listing_known_make, label: 'Make', 
                        collection: vehicle_selection.make_choices,
                        input_html: {
                        class: 'vehicle-make form-control select2 jcf-ignore', 
                        id: 'photo-ad-order-form-listing-known-make',
                        data: {
                           target: 'photo-ad-order-form-listing-known-model',
                           placeholder: 'Any Make'
                       }
                    } %>  
      </div>

      <div class ="form-group clearfix">
          <%= f.input :listing_known_model, label: 'Model', 
                      collection: vehicle_selection.model_choices, 
                      input_html: {
                      class: 'vehicle-model form-control select2 jcf-ignore', 
                      id: 'photo-ad-order-form-listing-known-model',
                       data: {
                            placeholder: 'Any Model'
                             }
                          }
                       %>   
      </div>
</fieldset>

My call to this partial in the form partial _form.html.erb

<%= render partial: 'photo_ad_orders/make_select.html.erb', locals: {f: f} %>

So this works how I would expect it to, you select the make, and the model is filter as expected, I click to save the database, having set the correct target, symbols, and ids. It successfully saves your selection to the database.

[Sucessful form selection][2]

So now the problem

I thought I successfully complete the feature they wanted me to do, but upon QA testing of this feature, I determined that when a user clicks the edit button rails RENDERS the edit page. All content remains as it should powered by active record including the Make selected. BUT the model field is empty, when you click on the field, there i'snt any available models based of the make. The user must click the make field, select a different make(Audi) to fire the query, go back to the correct make(Aston Martin), the models are then listed(DB7, etc) and the user can select the correct model.

After clicking edit, this is the issue

So

  1. the selected model should be filled in when clicking edit
  2. the user at the very least should already be queried with available models, because the make is retained when re-rendering

I believe it because when I converted to simple form, I don't know how to include a nil case like in options_for_select(collection, collection)

So what I need is the correct way to convert this to simple_form

   <%= select_tag :model, options_for_select(vehicle_selection.model_choices, vehicle_selection.model),
               include_blank: true,
               class: 'vehicle-model form-control select2 jcf-ignore',
               data: {
                   placeholder: 'Any Model'
               } %>

Can you anyone tell me the correct way to convert this options_for_select using two collections in simple_form

I had more images but stackoverflow only let me use 2 because of reputation.


Solution

  • I determined that i needed to change the method and give the model input all the available models, and let the javascript handle the filtering.

    This works for me now.

     <div class ="form-group clearfix">
              <%= f.input :listing_known_model, label: 'Model', 
                          collection: vehicle_selection.all_model_choices, 
                          input_html: {
                          class: 'vehicle-model form-control select2 jcf-ignore', 
                          id: 'photo-ad-order-form-listing-known-model',
                           data: {
                                placeholder: 'Any Model'
                                 }
                              }
                           %>   
          </div>
    

    vehicle_selection.rb

    def model_choices @model_choices ||= make.present? ? model_source.call(make) : [] end

    def all_model_choices @all_model_choices ||= ->{ MakeModel.models } end