Rails 5: prepopulate search form inputs using form_with with params without having to do it manually for each field

Viewed 630

Let's say we have a simple search form that submits a GET request for searching/filtering:

<%= form_with(scope: :search, url: url_for, local: false, method: :get) do |f| %>
  <%= f.text_field :title %>
<% end %>

When we use form_with (or the old form_for) with an ActiveRecord object, all fields get automatically pre-filled with the current value of the AR object attribute.

But in the example above, if we use only a scope (in our case, search), that doesn't happen when we open the page with a URL like so:

http://localhost:3000/blog?search%5title%5D=test

Even tough that URL will make rails populate params[:search] with {title: 'test'} for us, it would still require to pass the value manually for each field, like so:

<%= f.text_field :title, value: params.dig(:search, :title) %>

This gets very tedious and error-prone as the search form grows and seems such a common requirement that I can't believe there isn't a more 'rails way' of doing this without resorting to something like the Form Objects Design Pattern.

Isn't there any automatic way of pre-filling those inputs without having to pass the values manually from params?

2 Answers

Search is not a model in my application

You can create as many models as you like. This model will hold the values and logic for your search. When you pass this object into form_for it will fill the values that are set for the attributes in the object. Create the following class in your models directory

class Search
  include ActiveModel::Model

  attr_accessor :title

  validates :title, presence: true
end
  • By including the include ActiveModel::Model you get logic for 'free'. Such as Search.new(params) and it will assign all keys in the params hash to your model attributes (as long as they are defined by attr_accessor
  • You get validations which could be pretty handy when you want to give feedback to the user that is using your search form
  • Later when your search model gets more logic write unit test for this model

I think you could create a new search object with the values of the params in your controller action. Then the form_with/form_for should pre-fill the input fields. Maybe like this:

@search = Search.new(params[:search])

Hope that helps.

Related