Skip to content

Controllers

  • Trek::BaseController — the base for all admin controllers: authentication, authorization, localization, the admin layout and Trek's form builder.
  • Trek::ResourceController — extends BaseController with the full CRUD (index, show, new, create, edit, update, destroy), wired to ActionPolicy (authorized_scope, authorize!) and ordering. Scaffolded controllers inherit from it and only need to declare their model:
ruby
module Admin
  class BooksController < Trek::ResourceController
    private

    def model
      Book
    end
  end
end
  • Panel controllers (Trek::Panels::*) — support endpoints used by the admin UI: image uploads (Uppy), link insertion and content editor prompts.

Mixins

  • include Trek::Pagination — paginates the index with Kaminari
  • include Trek::Search — filters the index by params[:search] when the model is Searchable
  • include Trek::Filters — filters the index by attribute equality (where(column => value)) from params[:filters]
  • include Trek::Scopes — filters the index by named scopes from params[:scopes]

Filters

Trek::Filters lets users narrow an index by attribute values. Call apply_filters! in your index action — it rewrites @objects from params[:filters], applying a where(column => value) per non-blank filter (a value of "nil" matches NULL):

ruby
module Admin
  class CitiesController < Trek::ResourceController
    include Trek::Filters

    helper_method :countries

    def index
      super
      apply_filters!
    end

    private

    def countries
      City.distinct.pluck(:country_code).index_with { |code| I18n.t("countries.#{code}") }
    end
  end
end

Render the choices with a ButtonGroupComponent, each button linking back to the index with the chosen filter:

slim
= render Trek::ButtonGroupComponent.new do |g|
  - g.with_button text: t("admin.actions.all"), \
      href: [:admin, model], active: params.dig(:filters, :country_code).nil?
  - countries.each do |code, name|
    - g.with_button text: name, \
        href: polymorphic_path([:admin, model], filters: { country_code: code }), \
        active: code == params.dig(:filters, :country_code)

If a controller includes Trek::Filters but its index never calls apply_filters!, an after_action raises Trek::Filters::NotAppliedError (outside production) to flag the missing wiring.

Scopes

Trek::Scopes filters by named model scopes rather than raw attributes. Declare the allowed scopes via available_scopes, then call apply_scopes! in your index. It also exposes scope_counts and unscoped_objects helpers (the per-scope match counts and the pre-scope collection) for building scope tabs:

ruby
module Admin
  class ArticlesController < Trek::ResourceController
    include Trek::Scopes

    def index
      super
      apply_scopes!
    end

    private

    def available_scopes
      %i[published draft]
    end
  end
end

Like Trek::Filters, forgetting to call apply_scopes! raises Trek::Scopes::NotAppliedError outside production.

Released under the MIT License.