Ransack follows semantic versioning: a major release is the only place a breaking change can land. This page lists what changed in each major release and what to do about it. The full list of changes in every release is in the GitHub release notes.
Upgrading to 6.0
Ruby 3.2 or later is required
Ruby 3.1 reached end of life in March 2025 and no longer receives security fixes. Ransack 6.0 requires Ruby 3.2 or later, which is also the floor for Rails 8.0. If you are on Ruby 3.1 you are already limited to Rails 7.2; stay on Ransack 5.x until you can upgrade Ruby.
cont is case-sensitive on PostgreSQL
Ransack never told Arel whether a LIKE should be case-sensitive, and Arel’s
PostgreSQL visitor renders the default as ILIKE. So on PostgreSQL cont,
start, end and matches all ignored case, while the docs said cont used
LIKE. They now do: cont is LIKE and i_cont is ILIKE. A PostgreSQL
application that relied on cont ignoring case should switch those searches
to i_cont. MySQL and SQLite are unaffected; their LIKE follows the
column’s collation as before. See
Search Matchers.
Database dialects are detected from the adapter class
A few places generate different SQL per database. They used to compare the
adapter’s name against a list ("PostgreSQL", "PostGIS", "Mysql2",
"Trilogy"), so an adapter that was not on the list — even one built on a
known adapter — got the wrong SQL, and PostGIS was carried as a development
dependency just to keep it on the list. The dialect is now read from the
adapter class’s ancestry, so PostGIS is PostgreSQL without being named, and
config.dialect overrides the detection. The activerecord-postgis-adapter
development dependency and its CI job are gone. See
Configuration.
Strict searches check more
Under ransack! or ignore_unknown_conditions = false, two things that were
silently accepted now raise Ransack::InvalidSearchError:
- a sort on an attribute that is not ransortable or does not exist, which used
to drop the whole
ORDER BY(see Sorting); - a condition name that mixes
_and_and_or_, which used to apply the first combinator to every attribute (see Simple Mode).
Permissive searches are unchanged.
Values are cast by the declared attribute type
A column redeclared with attribute :name, :datetime is now cast as a
datetime; before, the schema column’s type won. A Date given for a datetime
column now means midnight in Time.zone; before, it was midnight in the
server’s system time zone, which moved the day boundary when the two differed.
See Search Matchers.
Scopes that skip sanitizing receive false
A scope listed in ransackable_scopes_skip_sanitize_args now receives a bare
false instead of being skipped, so it can be driven by a yes / no / any
select. Other scopes still treat false as an unticked checkbox. See
Other notes.
Joins already on the relation are reused
A search on a relation that already joins a table, through joins,
left_outer_joins, an eager-loaded includes or a previous search, now
reuses that join. Before, the association was joined again under a fresh
alias, which multiplied rows for a has_many and could bind a condition to
the wrong one of two joins to the same table. A query that depended on the
duplicate is unlikely, but row counts from such searches will change. The
joins Ransack adds are now stashed on the relation’s left_outer_joins
rather than its joins; code that inspected joins_values for them should
look at left_outer_joins_values. See
Associations.
sorts= replaces instead of appending
search.sorts = 'name asc' now sets exactly that sort; before, it added to
whatever sorts the search already had, and sorts = [] did nothing. Code that
relied on the append should call build_sort for each additional sort. See
Sorting.
A scope wins over an attribute of the same name in the writer
Search#build already applied a ransackable_scopes entry before looking for
an attribute of the same name; the attribute writer and reader used by form
builders (search.salary = 100, f.check_box :salary) checked attributes
first and silently skipped the scope. They agree now.
ransack_alias resolves through associations and in compounds
author_name_cont (alias on Author) and text_or_author_name_cont used to
produce SQL referring to columns that do not exist; they now expand the alias.
The alias name itself no longer needs to be in ransackable_attributes, and an
alias whose target does not exist raises under ransack! like any unknown
attribute. See
Ransack Aliases.
Polyamorous is gone; Ransack::Adapters::ActiveRecord is deprecated
The Active Record integration now lives under Ransack::ActiveRecord. See
How Ransack is built for the layout.
Ransack::Adapters::ActiveRecord::Baseand::Contextstill resolve, with a deprecation warning, and will be removed in 7.0. An initializer that reopensRansack::Adapters::ActiveRecord::Baseto change theransackable_*defaults should reopenRansack::ActiveRecord::Baseinstead.- The
Polyamorousnamespace and thepolyamorous/polyamorousrequire path are removed.Polyamorous::JoinisRansack::ActiveRecord::Join;Polyamorous::InnerJoinandOuterJoinwere aliases forArel::Nodes::InnerJoinandArel::Nodes::OuterJoin, so use those. Ransack::SUPPORTS_ATTRIBUTE_ALIASis removed; every supported Active Record version supports attribute aliases.Ransack::Context.for_classandfor_objectare replaced by a resolver registry,Ransack::Context.register, so another ORM can plug in without patching Ransack.
Upgrading to 5.0
Ransack 5.0 shipped on 2026-09-21 with these behaviour changes. Each is described in more detail on the page it links to.
LIKEwildcards (%and_) in search values are escaped on every database, and everyLIKEcarries an explicitESCAPEclause. A value of100%now matches the literal text100%. See Search Matchers.- Empty arrays and blank strings can be treated as real filter values with
config.ignore_blank_values = false. See Configuration. - An unknown combinator (
m:) raises underransack!orignore_unknown_conditions: falserather than silently meaningand, andOR/:orare normalised toor. See Advanced Mode. config.postgres_fields_sort_optionis renamedconfig.fields_sort_option, becauseNULLS FIRST/NULLS LASTare emitted through Arel and work on every database that supports them. The old name still works. See Sorting.- The monkey patch on
ActionView::Helpers::Tags::Base#valueis gone. Form fields read their values through the search object’s own readers, so nothing changes forsearch_form_for, but code that depended on the patch indirectly should be checked.