Does Ransack Support PostgreSQL JSON and Array Columns? Complete Guide
Yes, Ransack fully supports PostgreSQL arrays, JSON, and JSONB columns through built-in array predicates and extensible ransacker methods that generate native PostgreSQL operators like @>.
Ransack provides a flexible search interface for Active Record models, and according to the activerecord-hackery/ransack source code, it handles PostgreSQL-specific data types without requiring external extensions. Whether you're querying integer arrays or searching within JSONB documents, the library's predicate system offers both native compatibility and custom extension points.
Native Array Support with the wants_array Flag
PostgreSQL array columns work seamlessly with Ransack's collection-based predicates. The implementation relies on a specific flag set during predicate initialization.
In lib/ransack/predicate.rb, the constructor sets the @wants_array instance variable based on the predicate type:
# lib/ransack/predicate.rb (lines 43-45)
@wants_array = opts.fetch(:wants_array,
@compound || Constants::IN_NOT_IN.include?(@arel_predicate))
This flag indicates that the predicate expects an array of values rather than a single scalar. When you use predicates like *_in, *_any, or *_all, Ransack automatically configures them to accept arrays.
Array Validation in Ransack::Nodes::Condition
Before generating SQL, Ransack validates that the supplied values match the predicate's expected arity. The valid_arity? method in lib/ransack/nodes/condition.rb checks the wants_array flag:
# lib/ransack/nodes/condition.rb (lines 72-74)
def valid_arity?
values.size <= 1 || predicate.wants_array
end
This validation allows array values to pass through when the predicate sets wants_array = true, while restricting other predicates to single values.
Querying JSON and JSONB Columns
Ransack handles JSON data through two primary patterns: ransackers for fixed-key extraction and custom predicates for containment operations.
Searching Fixed JSON Keys with Ransackers
For predictable JSON schemas, define a ransacker that extracts the specific key using PostgreSQL's JSON operators:
# app/models/product.rb
class Product < ApplicationRecord
ransacker :color do |parent|
Arel.sql("products.specs ->> 'color'")
end
end
This creates a searchable attribute that maps to the SQL expression products.specs ->> 'color', allowing standard predicates:
Product.ransack(color_eq: 'red').result
# Generates: WHERE (products.specs ->> 'color') = 'red'
Custom Predicates for JSON Containment
To use PostgreSQL's @> (contains) operator for JSONB columns, register a custom predicate in your initializer:
# config/initializers/ransack.rb
Ransack.configure do |config|
config.add_predicate 'jcont',
arel_predicate: 'contains',
formatter: proc { |v| JSON.parse(v) }
end
Now you can query JSONB containment:
User.ransack(metadata_jcont: '{"role":"admin"}').result
# Generates: WHERE "users"."metadata" @> '{"role":"admin"}'
Practical Implementation Examples
Here are complete implementations for common PostgreSQL search scenarios.
1. Querying Integer Arrays
Search for records where an array column contains any of the specified values:
# Assuming tags is an integer[] column
Article.ransack(tags_id_in: [2, 5, 7]).result
# Generates: WHERE "articles"."tags_id" IN (2, 5, 7)
Or using the contains operator for array overlap:
Article.ransack(tags_contains: [2, 5]).result
# Generates: WHERE "articles"."tags" @> ARRAY[2,5]
2. JSONB Key Search via Ransacker
Extract and search nested JSON values:
class Contact < ApplicationRecord
ransacker :city do |parent|
Arel.sql("contacts.data ->> 'city'")
end
end
Contact.ransack(city_eq: 'Berlin').result
3. Advanced JSONB Containment
Combine custom predicates with the ActiveRecordExtended gem for complex JSONB queries:
# Requires ActiveRecordExtended for Arel.contains support
Ransack.configure do |config|
config.add_predicate(
'jcont',
arel_predicate: 'contains',
formatter: proc { |v| JSON.parse(v) }
)
end
# Search for users with specific metadata
User.ransack(metadata_jcont: '{"active":true,"plan":"pro"}').result
Summary
- Array columns: Fully supported via built-in predicates (
*_in,*_any) that setwants_array = trueinlib/ransack/predicate.rband validate arity inlib/ransack/nodes/condition.rb. - JSON/JSONB fixed keys: Use
ransackerblocks with PostgreSQL JSON operators (->>,->) to create searchable virtual attributes. - JSON containment: Extend Ransack with custom predicates mapping to Arel's
containsmethod to leverage the@>operator. - No external dependencies: Core array support works without additional gems, while advanced JSON containment requires only standard Arel extensions.
Frequently Asked Questions
Does Ransack require additional gems to search PostgreSQL arrays?
No. According to the source code in lib/ransack/predicate.rb and lib/ransack/nodes/condition.rb, array support is built into the core library through the wants_array flag. Predicates like *_in and *_any handle PostgreSQL arrays natively without requiring configuration changes or external dependencies.
How do I search inside a JSONB column for a specific key value?
Define a ransacker in your model that extracts the JSON key using PostgreSQL's ->> operator. This creates a virtual attribute you can query with standard predicates like eq or cont. For example, ransacker :city { Arel.sql("table.column ->> 'city'") } allows city_eq: 'Paris' queries.
Can Ransack use PostgreSQL's JSON containment operator (@>)?
Yes, but you must configure a custom predicate. Add a predicate via Ransack.configure that sets arel_predicate: 'contains' and includes a formatter to parse JSON strings. This maps to the @> operator in generated SQL, enabling efficient JSONB document searches.
Where is PostgreSQL-specific documentation located in the Ransack repository?
The official guide for PostgreSQL features resides at docs/docs/going-further/searching-postgres.md in the activerecord-hackery/ransack repository. This documentation covers both array and JSON/JSONB querying patterns with additional examples beyond the core implementation details.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →