Working with All Futures is very similar to working with a Rails model class. Depending on what you want to build, you will define the attributes, validations, callbacks and instance methods you need.
Define a class that inherits from
AllFutures, in a location that makes sense for your application. Many times,
app/models is a suitable home but in the example, an
app/filters folder was created.
Your first task is to define attributes representing the data structure you intend to persist.
attribute supports all of the same data types you could use in a migration:
app/filters/customer_filter.rbclass CustomerFilter < AllFutures# Facetsattribute :search, :stringattribute :threshold, :float, default: 0.1attribute :status, :stringattribute :lawyers, :boolean, default: falseattribute :low, :integer, default: 21attribute :high, :integer, default: 65# Paginationattribute :items, :integer, default: 10attribute :page, :integer, default: 1# Sortingattribute :order, :string, default: "name"attribute :direction, :string, default: "asc"end
The above code is an example of using All Futures to implement an exclusion filter. It's taken from the Beast Mode repo, and is used to hold the values required to create a faceted search UI for a tabular dataset.
When working with tabular data, there are typically three concerns:
Facets: attributes used to exclude and filter data from the total pool of possible values
Pagination: attributes used to track the current page and number of items per page
Sorting: attributes used to sort the filtered results in a specific direction (ASC vs DESC)
CustomerFilter doesn't describe the data - that's the model's job. Instead, facets describe the ways a user might exclude rows. Facets are composable, meaning that you can add them together to remove more data. Ultimately, the filter that is applied is the sum total of all active facets.
For example, the
lawyers attribute is used to reduce the results to only rows where the name of the employer has the string
and in it.
threshold is used to alternate between loose and strict text matching.
Since this example doesn't require any attribute validation, we complete the Filter by defining a
scope method to return an
ActiveRecord::Relation object. You can pass this relation directly into Pagy to perform the search, or additional scope clauses can be added to suit the needs of your application.
class CustomerFilter < AllFutures# Attribute definitions cut for brevitydef scopeCustomer.with_status(status).only_lawyers(lawyers).between(low, high).order(order => direction).search_for(search, threshold)endend
The business logic required to filter the data is fully contained in the model as a set of scopes. This
CustomerFilter#scope method simply connects the dots to provide access to a relation for this filter instance.
Going through building the rest of a faceted search is beyond the scope of this document, but you are encouraged to clone and explore the Beast Mode codebase and/or follow along with the tutorial blog post.