Ruby on Rails如何实现文本框与下拉选项结合的输入组件?
Hey there! Let's figure out how to swap those static select dropdowns for flexible input components that let users either type custom values or pick from predefined options—exactly like a datalist, perfect for your vehicle filters (price, year, km). Here are a few practical approaches tailored for your Rails app:
1. Native HTML5 <datalist> (Zero Dependencies, Quick Win)
This is the simplest option since it’s built directly into browsers, no extra libraries needed. Users can type freely or select from your predefined options, just like you want.
Rails View Example
Replace your select_tag inputs with text_field_tag paired with a <datalist>:
<%= form_tag(filter_vehicles_path, method: 'get') do %> <!-- Price Filters --> <span>Preço</span> <%= text_field_tag :price_start, params[:price_start], list: 'price-options', placeholder: "--de--" %> <datalist id="price-options"> <% ["250 EUR", "500 EUR", "1000 EUR", ..., "200 000 EUR"].each do |price| %> <option value="<%= price %>"><%= price %></option> <% end %> </datalist> <%= text_field_tag :price_ending, params[:price_ending], list: 'price-options', placeholder: "--até--" %> <!-- Year Filters --> <span>Ano</span> <%= text_field_tag :year_start, params[:year_start], list: 'year-options', placeholder: "--de--" %> <datalist id="year-options"> <% ["1990", "1980", "1970", ..., "1900"].each do |year| %> <option value="<%= year %>"><%= year %></option> <% end %> </datalist> <%= text_field_tag :year_ending, params[:year_ending], list: 'year-options', placeholder: "--até--" %> <!-- KM Filters --> <span>Quilómetros</span> <%= text_field_tag :kms_start, params[:kms_start], list: 'kms-options', placeholder: "--de--" %> <datalist id="kms-options"> <% ["5 000 km", "10 000 km", ..., "500 000 km"].each do |km| %> <option value="<%= km %>"><%= km %></option> <% end %> </datalist> <%= text_field_tag :kms_end, params[:kms_end], list: 'kms-options', placeholder: "--até--" %> <%= submit_tag "Pesquisar" %> <% end %>
Key Notes
- Pros: No extra code to install, lightweight, works on all modern browsers.
- Cons: Limited styling control (browser default styles vary), no advanced features like search.
- Parameter Cleaning: Since users might type values with units (like "1500 EUR"), you’ll need to strip non-numeric characters before passing to your
named_scope:# In your VehiclesController#filter action price_start = params[:price_start]&.gsub(/\D/, '').to_i # Removes EUR, spaces, etc. price_ending = params[:price_ending]&.gsub(/\D/, '').to_i year_start = params[:year_start]&.gsub(/\D/, '').to_i kms_start = params[:kms_start]&.gsub(/\D/, '').to_i @vehicles = Vehicle.price_start(price_start).price_ending(price_ending)...
2. Frontend UI Libraries (Better Styling & Interaction)
If you want consistent cross-browser styling, searchable options, and more control, use a library like Select2 or Chosen. Both support custom user input while keeping predefined dropdown options.
Select2 Example
- Install via Yarn:
yarn add select2 - Import in your JS/CSS:
// app/javascript/packs/application.js import 'select2'; import 'select2/dist/css/select2.css'; document.addEventListener('DOMContentLoaded', () => { $('.select2-filter').select2({ placeholder: function() { $(this).data('placeholder'); }, allowClear: true, tags: true // Lets users type custom values }); }); - Update your Rails view:
<span>Preço</span> <%= select_tag :price_start, options_for_select(["250 EUR", ..., "200 000 EUR"], params[:price_start]), prompt: "--de--", class: "select2-filter", data: { placeholder: "--de--" } %> <%= select_tag :price_ending, options_for_select(["250 EUR", ..., "200 000 EUR"], params[:price_ending]), prompt: "--até--", class: "select2-filter", data: { placeholder: "--até--" } %>
Chosen Example
Similar to Select2, but with a simpler API:
- Install via Yarn:
yarn add chosen-js - Import and initialize:
// app/javascript/packs/application.js import 'chosen-js'; import 'chosen-js/chosen.css'; document.addEventListener('DOMContentLoaded', () => { $('.chosen-filter').chosen({ allow_single_deselect: true, enable_search_threshold: 10, // Shows search box when there are many options search_contains: true }); }); - View code:
<%= select_tag :price_start, options_for_select(["250 EUR", ...], params[:price_start]), prompt: "--de--", class: "chosen-filter" %>
3. Rails-Specific Gems (Seamless Integration)
If you prefer using Rails form helpers with minimal setup, pair Simple Form with the libraries above. For example:
<%= simple_form_for :filter, url: filter_vehicles_path, method: :get do |f| %> <%= f.input :price_start, as: :select, collection: ["250 EUR", ..., "200 000 EUR"], include_blank: "--de--", input_html: { class: "select2-filter", data: { tags: true } } %> <% end %>
Final Tips for Your named_scope
Make sure your scopes handle empty values gracefully to avoid invalid SQL:
# In your Vehicle model scope :price_start, ->(price) { where('price >= ?', price) if price.present? } scope :price_ending, ->(price) { where('price <= ?', price) if price.present? } scope :year_start, ->(year) { where('year >= ?', year) if year.present? } scope :kms_start, ->(kms) { where('kms >= ?', kms) if kms.present? }
内容的提问来源于stack exchange,提问作者Proz1g

