Skip to main content

Saved Views

Overview​

Saved Views let each user save the current state of an index page under a name and come back to it in one click. A view stores:

  • Search and filters (standard and advanced)
  • Sort
  • Visible and hidden columns, including column order (Manage Columns)
  • Records per page
  • View type (table, card, kanban)

Views are private to their owner (Current.user) and are scoped per model. Associated (tab) tables keep their own separate set of views.

Saved Views replace the old Index Preference feature (cm_index_preferences).

Setup​

1. Run the generator​

rails generate cm_admin:ct_page_view
rails db:migrate

The migration:

  • Enables the PostgreSQL citext extension, so view names are case-insensitive.
  • Drops the legacy cm_index_preferences table if it exists. Its data is not migrated.
  • Creates ct_page_views:
ColumnTypeNotes
ownerpolymorphic referenceRequired. Set to Current.user
namecitextRequired
ar_model_namestringModel whose index page the view belongs to
associated_ar_model_namestring, default ''Parent model when the view is on an associated tab
visible_columnsstring[]Ordered
hidden_columnsstring[]
is_defaultbooleanAt most one per owner / model (partial unique index)
view_typeinteger enumtable: 0, card: 1, kanban: 2
records_per_pageinteger, default 20
filter_paramsjsonbDecoded filters hash
sort_paramsjson

See Generators.

2. Requirements​

  • DEFAULT_PER_PAGE must be defined (it is generated in config/initializers/constants.rb). PER_PAGE_OPTIONS is optional and defaults to [10, 20, 50, 100].
  • Current.user must be set for admin requests.
  • PaperTrail must be set up. CtPageView uses has_paper_trail.

There is no DSL to add: Saved Views appear on every index page and associated table.

Usage​

ActionHow
Save a viewSet filters, sort, and columns, then Save View, enter a name, and Save
Apply a viewSaved Views, then click the view
Update a viewApply it, then change filters, sort, columns, or page size. Changes are auto-saved to the active view
Clear the active viewClick × on the view button. This returns to the unfiltered page
Set as defaultUse the ⋼ menu, then Set as Default. The view opens automatically when you visit the page
OthersUse the ⋼ menu: Copy Link, Edit (rename), Duplicate, Delete

Default view behaviour​

When a user opens an index page with no filters, current_ct_page_view_id, clear_filters, or clear_ct_page_view params, they are redirected to their default view. Links that already carry any of these params, such as shared filtered links, open as-is.

A view applies itself through query params: current_ct_page_view_id, filters, sort, and view_type. Copy Link copies these params. Because views belong to their owner, other users only get the filters, sort, and view type from the link, not your saved columns.

Routes​

These routes are added automatically for every cm-admin model, with no setup needed:

VerbPathAction
GET/<models>/ct_page_viewslist_ct_page_view
POST/<models>/ct_page_viewscreate_ct_page_view
PUT/<models>/ct_page_views/:idupdate_ct_page_view
DELETE/<models>/ct_page_views/:iddestroy_ct_page_view
POST/<models>/ct_page_views/:id/duplicateduplicate_ct_page_view

Route helpers follow the pattern <action>_ct_page_view_<model>_path, for example create_ct_page_view_user_path. The list route's helper is ct_page_view_<model>_path.

Working with CtPageView in Ruby​

view = CtPageView.create!(
owner: user,
name: 'Active adults',
ar_model_name: 'User',
filter_params: { advanced: [{ filter_type: 'single_select', filter_name: 'status', condition: 'is', value: 'active' }] },
sort_params: { created_at: { dir: 'desc', type: nil } },
visible_columns: %w[name email status],
records_per_page: 50,
is_default: true
)

view.apply_params # => { current_ct_page_view_id: 1, filters: "eJy...", sort: { "created_at" => { ... } } }
view.apply_url # => index path with the params above

Setting is_default: true automatically unsets the previous default for the same owner, model, and associated model.

Upgrading from Index Preference​

See the v8.2.0 upgrade guide.