Skip to content

rzane/advanced_demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Advanced Demo

This is a demo of the (Advanced)[https://github.com/rzane/advanced] gem.

It shows the largest 1,000 cities in the United States.

Basic Example

The StateSearch. This object is responsible for querying the states table.

class StateSearch < Advanced::Search
  def search_name(name:, **)
    where('states.name like ?', "%#{name}%")
  end
end

We can use our StateSearch like this:

StateSearch.call(State.all, name: 'New')
# => SELECT * FROM states WHERE states.name like '%New%'

By extending the scope in our State model, we can shorten this a bit.

class State < ApplicationRecord
  extend StateSearch.scope
end

State.search(name: 'New')

Within the StateSearch class, we'll also define a form object, StateSearch::Form.

class StateSearch < Advanced::Search
  # ...
  class Form < Advanced::SearchForm
    search StateSearch
  end
end

It's basically a hash, except that it's compatible with Rails' form builder.

form = StateSearch::Form.new(name: 'New')
form.name #=> 'New'
State.search(form)
# => SELECT * FROM states WHERE states.name like '%New%'

In our controller, we're going to initialize a form from the incoming params hash and query for States.

class StatesController < ApplicationController
  def index
    @form   = StateSearch::Form.new(params[:q])
    @states = State.order(:name).search(@form)
  end
end

In this file, we'll wire everything up. There's no magic here. We're just using Rails built-in functionality to create our form.

<h1 class="page-header">
  States
</h1>

<div class="row">
  <div class="col-md-8">
    <table class="table table-striped table-bordered">
      <thead>
        <tr>
          <th>Name</th>
        </tr>
      </thead>

      <tbody>
        <% @states.each do |state| %>
          <tr>
            <td><%= state.name %></td>
          </tr>
        <% end %>
      </tbody>
    </table>
  </div>

  <div class="col-md-4">
    <%= form_for @form, method: :get, url: states_path, as: :q do |f| %>
      <div class="form-group">
        <%= f.label :name, class: 'control-label' %>
        <%= f.text_field :name, class: 'form-control' %>
      </div>

      <%= f.submit 'Search', class: 'btn btn-primary' %>
      <%= link_to 'Reset', states_path, class: 'btn btn-default' %>
    <% end %>
  </div>
</div>

A More Complicated Example

For listing cities, we'll do a more complicated query. Advanced is designed to be composable, so we can take advantage of the StateSearch that we already built.

class CitySearch < Advanced::Search
  def search_name(name:, **)
    where('cities.name like ?', "%#{name}%")
  end

  def search_state(state:, **)
    joins(:state).merge State.search(state)
  end
end

We can use our CitySearch like this:

CitySearch.call(City.all, name: 'New York')
#=> SELECT  "cities".* FROM "cities" WHERE (cities.name like '%New York%')

CitySearch.call(City.all, state: { name: 'New York' })
#=> SELECT  "cities".* FROM "cities"
#=> INNER JOIN "states" ON "states"."id" = "cities"."state_id"
#=> WHERE (states.name like '%New York%')

Again, we can abbreviate this by adding the scope to our model:

class City < ApplicationRecord
  extend CitySearch.scope
end
City.search(name: 'New York')

We can also implement nested forms. Doing so will allow us to take advantage of Rails' fields_for.

class CitySearch < Advanced::Search
  # ...
  class Form < Advanced::SearchForm
    search CitySearch
    nested :state, StateSearch::Form
  end
end

We can use the CitySearch::Form like this:

form = CitySearch::Form.new(name: 'New York', state: { name: 'New York' })
form.name #=> 'New York'
form.state.name #=> 'New York'

City.search(form)
#=> SELECT  "cities".* FROM "cities"
#=> INNER JOIN "states" ON "states"."id" = "cities"."state_id"
#=> WHERE (cities.name like '%New York%') AND (states.name like '%New York%')

As before, we'll wire up our controller:

class CitiesController < ApplicationController
  def index
    @form   = CitySearch::Form.new(params[:q])
    @cities = City.includes(:state).order(:rank).search(@form)
  end
end

This file is very similar to the states example, except that in order to query the states table, we'll use Rails fields_for.

<%= form_for @form, method: :get, url: cities_path, as: :q do |f| %>
  ...

  <%= f.fields_for :state do |state| %>
    <div class="form-group">
      <%= state.label :name, 'State', class: 'control-label' %>
      <%= state.text_field :name, class: 'form-control' %>
    </div>
  <% end %>
<% end %>

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages