### Install Documentation Dependencies Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/documentation.md Install Docusaurus and other necessary packages for local documentation development. ```bash yarn install ``` -------------------------------- ### Controller Setup with Includes and Pagination Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Use this controller setup for sorting on associated table columns without `distinct: true`. It includes preloading associated records and pagination. ```ruby def index @q = Person.ransack(params[:q]) @people = @q.result.includes(:articles).page(params[:page]) end ``` -------------------------------- ### Install Development Dependencies Source: https://github.com/activerecord-hackery/ransack/blob/main/CONTRIBUTING.md Installs the necessary gems for development. Specify a Rails version if not using the latest. ```sh bundle install ``` ```sh RAILS='6-1-stable' bundle install ``` -------------------------------- ### Start Local Development Server Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/documentation.md Launch a local development server to preview documentation changes in real-time. Changes are typically reflected live without needing a server restart. ```bash yarn start ``` -------------------------------- ### Basic Controller Setup - Ransack Simple Mode Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Use this in your controller to initialize a Ransack search object with distinct results. Ensure `params[:q]` is available. ```ruby def index @q = Person.ransack(params[:q]) @people = @q.result(distinct: true) end ``` -------------------------------- ### Starts With Predicate Source: https://github.com/activerecord-hackery/ransack/wiki/Basic-Searching Use the `start` predicate to find records where a field begins with a specific string. This is case-sensitive. ```ruby >> User.ransack(first_name_start: 'Rya').result.to_sql => SELECT "users".* FROM "users" WHERE ("users"."first_name" LIKE 'Rya%') ``` -------------------------------- ### Controller Setup for Ransack Search Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/associations.md In your controller, initialize a Ransack search object with parameters and eager load associated records for performance. ```ruby class SupervisorsController < ApplicationController def index @q = Supervisor.ransack(params[:q]) @supervisors = @q.result.includes(:department, :employees) end end ``` -------------------------------- ### Ransack Console Examples for Authorization Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/other-notes.md Demonstrates how `ransackable_attributes` behaves with and without an `auth_object` in the Rails console. ```ruby > Article => Article(id: integer, person_id: integer, title: string, body: text) > Article.ransackable_attributes => ["title", "body"] > Article.ransackable_attributes(:admin) => ["id", "person_id", "title", "body"] > Article.ransack(id_eq: 1).result.to_sql => SELECT "articles".* FROM "articles" # Note that search param was ignored! > Article.ransack({ id_eq: 1 }, { auth_object: nil }).result.to_sql => SELECT "articles".* FROM "articles" # Search param still ignored! > Article.ransack({ id_eq: 1 }, { auth_object: :admin }).result.to_sql => SELECT "articles".* FROM "articles" WHERE "articles"."id" = 1 ``` -------------------------------- ### Ransack Search with Scopes Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/other-notes.md Example of performing a Ransack search using defined scopes. The second example demonstrates passing an `auth_object` to filter scopes. ```ruby Employee.ransack({ activated: true, hired_since: '2013-01-01' }) ``` ```ruby Employee.ransack({ salary_gt: 100_000 }, { auth_object: current_user }) ``` -------------------------------- ### Ransacker with Arguments Source: https://context7.com/activerecord-hackery/ransack/llms.txt Use ransackers with arguments to perform complex attribute searches. This example searches for articles where the title contains 'Guide' and the body length is within a specified range. ```ruby Person.ransack( conditions: [{ attributes: { '0' => { name: 'max_article_title_by_body_length', ransacker_args: [10, 100] } }, predicate_name: 'cont', values: ['Guide'] }] ) ``` -------------------------------- ### Usage of Custom Predicates Source: https://context7.com/activerecord-hackery/ransack/llms.txt Demonstrates how to use custom Ransack predicates in queries. Includes examples for null-safe greater-than-or-equal-to and JSONB containment. ```ruby # Usage ``` ```ruby Product.ransack(price_gteq_or_null: 100).result.to_sql ``` ```ruby # => SELECT "products".* FROM "products" WHERE ("products"."price" >= 100 OR "products"."price" IS NULL) ``` ```ruby # JSONB contains usage ``` ```ruby Person.ransack(data_jcont: '{"group": "experts"}').result.to_sql ``` ```ruby # => SELECT "persons".* FROM "persons" WHERE "persons"."data" @> '{"group": "experts"}' ``` -------------------------------- ### Controller Setup for Ransack Authorization Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/other-notes.md In your controller, initialize Ransack with a potential `auth_object` derived from the current user. ```ruby class ArticlesController < ApplicationController def index @q = Article.ransack(params[:q], auth_object: set_ransack_auth_object) @articles = @q.result end private def set_ransack_auth_object current_user.admin? ? :admin : nil end end ``` -------------------------------- ### Add Ransack to Gemfile Source: https://github.com/activerecord-hackery/ransack/blob/main/README.md To install Ransack, add the gem to your Gemfile. ```ruby gem 'ransack' ``` -------------------------------- ### Configure Routes for Advanced Search Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/advanced-mode.md Define a collection route for 'search' that accepts both GET and POST requests. This is necessary for advanced searches that may exceed GET request size limits. ```ruby resources :people do collection do match 'search' => 'people#search', via: [:get, :post], as: :search end end ``` -------------------------------- ### Basic Ransack Controller and View Setup Source: https://context7.com/activerecord-hackery/ransack/llms.txt In the controller, call `.ransack(params[:q])` on your model. In the view, use `search_form_for` and `sort_link` helpers to build the search form and sortable table headers. ```ruby # app/controllers/people_controller.rb def index @q = Person.ransack(params[:q]) @people = @q.result(distinct: true).includes(:articles).page(params[:page]) end ``` ```erb <%# app/views/people/index.html.erb %> <%= search_form_for @q do |f| %> <%= f.label :name_cont, "Name contains" %> <%= f.search_field :name_cont %> <%= f.label :name_or_email_cont, "Name or email contains" %> <%= f.search_field :name_or_email_cont %> <%= f.label :articles_title_start, "Article title starts with" %> <%= f.search_field :articles_title_start %> <%= f.submit "Search" %> <% end %> <% @people.each do |person| %> <% end %>
<%= sort_link(@q, :name, "Full Name", default_order: :asc) %> <%= sort_link(@q, :email) %> <%= sort_link(@q, :age) %>
<%= person.name %> <%= person.email %> <%= person.age %>
``` -------------------------------- ### Usage of Ransackers Source: https://context7.com/activerecord-hackery/ransack/llms.txt Examples demonstrating how to query using defined ransackers for concatenated names, string-casted IDs, and other custom attributes. ```ruby # Usage examples ``` ```ruby Person.ransack(full_name_cont: 'john doe').result.to_sql ``` ```ruby # => ... WHERE (LOWER(concat_ws(' ', first_name, last_name)) LIKE '%john doe%') ``` ```ruby Person.ransack(id_cont: '42').result.to_sql ``` ```ruby # => ... WHERE (to_char(id, '9999999') LIKE '%42%') ``` -------------------------------- ### Usage of Ransacker with Arguments Source: https://github.com/activerecord-hackery/ransack/wiki/Using-Ransackers Demonstrates how to pass arguments to a ransacker using `ransacker_args` when performing a search. This example searches for people whose maximum article title meets certain criteria. ```ruby Person.ransack( conditions: [{ attributes: { '0' => { name: 'author_max_title_of_article_where_body_length_between', ransacker_args: [10, 100] } }, predicate_name: 'cont', values: ['Ransackers can take arguments'] }] ) => SELECT "people".* FROM "people" WHERE ( (SELECT MAX(articles.title) FROM articles WHERE articles.person_id = people.id AND CHAR_LENGTH(articles.body) BETWEEN 10 AND 100 GROUP BY articles.person_id ) LIKE '%Ransackers can take arguments%') ORDER BY "people"."id" DESC ``` -------------------------------- ### Configure Ransack Globally Source: https://github.com/activerecord-hackery/ransack/wiki/Configuration Set global Ransack configuration options in an initializer file. This example shows how to change the default search key, disable ignoring unknown conditions, and hide sort order indicators. ```ruby Ransack.configure do |config| # Change default search parameter key name. # Default key name is :q config.search_key = :query # Raise errors if a query contains an unknown predicate or attribute. # Default is true (do not raise error on unknown conditions). config.ignore_unknown_conditions = false # Globally display sort links without the order indicator arrow. # Default is false (sort order indicators are displayed). # This can also be configured individually in each sort link (see the README). config.hide_sort_order_indicators = true end ``` -------------------------------- ### OR Queries on Associated Models Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/using-predicates.md Search across attributes of associated models using a combined predicate syntax. This example searches 'foo' or 'bar' on the associated 'account' model. ```ruby >> User.ransack(account_foo_or_account_bar_cont: 'val').result.to_sql => SELECT "users".* FROM "users" INNER JOIN accounts ON accounts.user_id = users.id WHERE ("accounts.foo LIKE '%val%' OR accounts.bar LIKE '%val%') ``` -------------------------------- ### Silent Failure Example Source: https://github.com/activerecord-hackery/ransack/wiki/Basic-Searching Attempting to use a predicate for a non-existent attribute will result in a silent failure, returning no SQL WHERE clause. ```ruby >> User.ransack(name_cont: 'Rya').result.to_sql => "SELECT \"users\".* FROM \"users\" ``` -------------------------------- ### Ransacker for Price Existence Check (PostgreSQL) Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/ransackers.md Creates a ransacker to check for the existence of a related record (e.g., 'prices' for a 'book'), returning a boolean. This example uses PostgreSQL syntax. ```ruby ransacker :price_exists do |parent| # SQL syntax for PostgreSQL -- others may differ # This returns boolean true or false Arel.sql("(select exists (select 1 from prices where prices.book_id = books.id))") end ``` -------------------------------- ### Ransacker for Concatenated Full Name with Quoted Space (Arel >= 6) Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/ransackers.md Similar to the previous example, but correctly quotes the space separator for Arel version 6 and above. ```ruby ransacker :full_name do |parent| Arel::Nodes::InfixOperation.new('||', Arel::Nodes::InfixOperation.new('||', parent.table[:first_name], Arel::Nodes.build_quoted(' ') ), parent.table[:last_name]) end ``` -------------------------------- ### Ransack Search with Tenant Scoping Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/acts-as-taggable-on.md Filter Ransack searches using the `for_tenant` method when multitenancy is configured for tags. This example shows selecting tags for a specific tenant ('fr'). ```erb
<%= f.label :projects_name, 'Project' %> <%= f.select :projects_name_in, ActsAsTaggableOn::Tag.for_tenant('fr').distinct.order(:name).pluck(:name) %>
``` -------------------------------- ### Handle Distinct Selects with Joins and Includes Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/other-notes.md When using `distinct: true` with joins, Ransack might generate invalid SQL. This example shows how to resolve this by adding `includes` and `joins` to the result. ```ruby def index @q = Person.ransack(params[:q]) @people = @q.result(distinct: true) .includes(:articles) .joins(:articles) .page(params[:page]) end ``` -------------------------------- ### jQuery AJAX Request with Ransack Parameters Source: https://context7.com/activerecord-hackery/ransack/llms.txt Example of sending Ransack search parameters via a jQuery AJAX request. Ensure the data is structured as a nested hash under the 'q' key. ```javascript // jQuery AJAX example $.ajax({ url: "/users.json", data: { q: { first_name_cont: "pete", last_name_cont: "jack", s: "created_at desc" } }, success: function(data) { console.log(data); } }); ``` -------------------------------- ### Add Custom Ransack Predicate Source: https://github.com/activerecord-hackery/ransack/wiki/Custom-Predicates Configure a new custom predicate named 'equals_diddly' using Ransack. This example demonstrates setting the Arel predicate, a custom formatter, a validator, and options for compounds, type casting, and case insensitivity. ```ruby Ransack.configure do |config| config.add_predicate 'equals_diddly', arel_predicate: 'eq', formatter: proc { |v| "#{v}-diddly" }, validator: proc { |v| v.present? }, compounds: true, type: :string, case_insensitive: true end ``` -------------------------------- ### Generate sortable column header links Source: https://context7.com/activerecord-hackery/ransack/llms.txt Use the `sort_link` helper to create links for sorting columns. It supports custom labels, default sort orders, and multi-column sorting. To get a sort URL string instead of a link tag, use `sort_url`. ```erb <%# Basic sort link %> <%= sort_link(@q, :name) %> ``` ```erb <%# Custom label and default direction %> <%= sort_link(@q, :name, 'Last Name', default_order: :desc) %> ``` ```erb <%# Block form for complex markup %> <%= sort_link(@q, :name) do %> Player Name <% end %> ``` ```erb <%# Multi-column sort: clicking sorts by last_name then first_name asc always %> <%= sort_link(@q, :last_name, [:last_name, 'first_name asc'], 'Last Name') %> ``` ```erb <%# Multi-column with per-field default orders %> <%= sort_link(@q, :last_name, %i(last_name first_name), default_order: { last_name: 'asc', first_name: 'desc' }) %> ``` ```erb <%# Hide the sort indicator arrow on this link only %> <%= sort_link(@q, :name, hide_indicator: true) %> ``` ```erb <%# Sort URL (returns URL string, not a link tag) %> <%= sort_url(@q, :name, default_order: :desc) %> ``` ```erb <%# Scope-based sort for computed/virtual fields — define scopes in model: scope :sort_by_reverse_name_asc, -> { order("REVERSE(name) ASC") } scope :sort_by_reverse_name_desc, -> { order("REVERSE(name) DESC") } %> <%= sort_link(@q, :reverse_name) %> ``` -------------------------------- ### Navigate to Docs Directory Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/documentation.md Change the current directory to the 'docs' folder to begin working with the documentation. ```bash cd docs ``` -------------------------------- ### Build Static Documentation Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/documentation.md Generate the static content for the documentation, which will be placed in the 'build' directory. This output can be hosted on any static content platform. ```bash yarn build ``` -------------------------------- ### Deploy Documentation via SSH Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/documentation.md Deploy the built documentation using SSH. This command assumes the necessary SSH keys and configurations are in place. ```bash USE_SSH=true yarn deploy ``` -------------------------------- ### Ransack Authorization Demonstration (Rails Console) Source: https://context7.com/activerecord-hackery/ransack/llms.txt Demonstrates how Ransack authorization works by showing the results of `ransackable_attributes` with and without an `auth_object`, and the SQL generated for authorized and unauthorized queries. ```ruby # Rails console demonstration Article.ransackable_attributes # => ["title", "body", "published_at"] Article.ransackable_attributes(:admin) # => ["id", "author_id", "title", "body", "published_at"] Article.ransack(id_eq: 1).result.to_sql # => SELECT "articles".* FROM "articles" (id_eq ignored — not authorized) Article.ransack({ id_eq: 1 }, { auth_object: :admin }).result.to_sql # => SELECT "articles".* FROM "articles" WHERE "articles"."id" = 1 ``` -------------------------------- ### Create MySQL Database Source: https://github.com/activerecord-hackery/ransack/blob/main/CONTRIBUTING.md Commands to connect to MySQL and create a database named 'ransack'. ```sh mysql -u root mysql> create database ransack; ``` -------------------------------- ### Search Fixed JSONB Key with Ransacker Source: https://context7.com/activerecord-hackery/ransack/llms.txt Define a ransacker to search a fixed key within a JSONB column. This example searches for 'link_type' in the 'properties' column. ```ruby class Contact < ApplicationRecord # Search a fixed key in JSONB ransacker :link_type do |parent| Arel::Nodes::InfixOperation.new('->>', parent.table[:properties], Arel::Nodes.build_quoted('link_type')) end # Cast entire JSONB column to text for string matching (slow; no index use) ransacker :within_json do |parent| Arel.sql("contacts.json_data::text") end def self.ransackable_attributes(auth_object = nil) _ransackers.keys end end ``` ```ruby # Search fixed JSONB key Contact.ransack(link_type_eq: 'twitter').result.to_sql # => SELECT "contacts".* FROM "contacts" WHERE "contacts"."properties" ->> 'link_type' = 'twitter' ``` ```ruby # Full-text JSON cast search Contact.ransack(within_json_cont: 'experts').result # => SELECT "contacts".* FROM "contacts" WHERE contacts.json_data ILIKE '%experts%' ``` ```ruby # Using jcont (requires custom predicate setup + ActiveRecordExtended gem): # Ransack.configure { |c| c.add_predicate 'jcont', arel_predicate: 'contains', formatter: proc { |v| JSON.parse(v) } } Person.ransack(data_jcont: '{"group": "experts"}').result.to_sql # => SELECT "persons".* FROM "persons" WHERE "persons"."data" @> '{"group": "experts"}' ``` -------------------------------- ### Basic Ransack Search Controller Source: https://context7.com/activerecord-hackery/ransack/llms.txt Sets up a Ransack search object in the controller and renders the results. Requires a corresponding view. ```ruby def search index render :index end def index @q = Person.ransack(params[:q]) @people = @q.result end ``` -------------------------------- ### Sort Link for Scoped Sorting Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Uses the `sort_link` helper to sort by a virtual field defined by a model scope. This example sorts by a scope named 'reverse_name'. ```erb <%= sort_link(@q, :reverse_name) %> ``` -------------------------------- ### Define Ransackable Scopes on a Model Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/other-notes.md Define `ransackable_scopes` on your model to whitelist scopes that Ransack can use. This example shows how to conditionally allow access to scopes based on an `auth_object`. ```ruby class Employee < ActiveRecord::Base scope :activated, ->(boolean = true) { where(active: boolean) } scope :salary_gt, ->(amount) { where('salary > ?', amount) } def self.hired_since(date) where('start_date >= ?', date) end def self.ransackable_scopes(auth_object = nil) if auth_object.try(:admin?) # allow admin users access to all three methods %i(activated hired_since salary_gt) else # allow other users to search on `activated` and `hired_since` only %i(activated hired_since) end end end ``` -------------------------------- ### Configure Model for Multitenancy with Acts As Taggable On Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/acts-as-taggable-on.md Enable tag scoping based on another model field, such as 'language', by using `acts_as_taggable_tenant`. This adds a second level of keying for tags. ```ruby class Task < ApplicationRecord acts_as_taggable_on :projects acts_as_taggable_tenant :language end ``` -------------------------------- ### Create PostgreSQL Database Source: https://github.com/activerecord-hackery/ransack/blob/main/CONTRIBUTING.md Command to create a PostgreSQL database named 'ransack', assuming OS X and Homebrew. ```sh createdb ransack ``` -------------------------------- ### Ransack Built-in Predicates: Start/End Source: https://context7.com/activerecord-hackery/ransack/llms.txt Use `_start` for searches that begin with a value and `_end` for searches that end with a value. ```ruby # start / end — starts with / ends with User.ransack(first_name_start: 'Rya').result.to_sql # => SELECT "users".* FROM "users" WHERE ("users"."first_name" LIKE 'Rya%') ``` -------------------------------- ### Define Ransack Alias for Associations Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/other-notes.md Use `ransack_alias` to create shorter, more readable search parameters for attributes involving associations. This example abbreviates a combined author name search. ```ruby class Post < ActiveRecord::Base belongs_to :author # Abbreviate :author_first_name_or_author_last_name to :author ransack_alias :author, :author_first_name_or_author_last_name end ``` -------------------------------- ### Run All Checks and Tests Source: https://github.com/activerecord-hackery/ransack/blob/main/CONTRIBUTING.md A comprehensive command to run RuboCop for style checks, the default Ransack test suite, and tests with PostgreSQL and MySQL. ```sh bundle exec rubocop && bundle exec rake spec && DB=pg bundle exec rake spec && DB=mysql bundle exec rake spec ``` -------------------------------- ### Ransacker for Integer to String Type Conversion Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/ransackers.md Convert an integer database field to a string to enable string-based searches like 'contains' on integer fields. This example uses PostgreSQL. ```ruby # in the model: ransacker :id_as_string, type: :string do Arel.sql('id::text') end ``` -------------------------------- ### Define Ransacker for Concatenated Full Name Source: https://github.com/activerecord-hackery/ransack/wiki/Using-Ransackers Define a ransacker to search on a concatenated full name from first and last names. This example shows basic concatenation and how to include a space. ```ruby ransacker :full_name do |parent| Arel::Nodes::InfixOperation.new('||', parent.table[:first_name], parent.table[:last_name]) end ``` ```ruby ransacker :full_name do |parent| Arel::Nodes::InfixOperation.new('||', Arel::Nodes::InfixOperation.new('||', parent.table[:first_name], ' ' ), parent.table[:last_name] ) end ``` -------------------------------- ### Global Ransack Configuration Source: https://context7.com/activerecord-hackery/ransack/llms.txt Configure Ransack globally via an initializer. Options include changing the search key, error handling, sort indicators, whitespace stripping, and PostgreSQL sort behavior. ```ruby # config/initializers/ransack.rb Ransack.configure do |config| # Change the default :q search param key config.search_key = :query # Raise an error for unknown predicates/attributes (default: true = ignore) config.ignore_unknown_conditions = false # Hide sort order arrow indicators globally config.hide_sort_order_indicators = true # Disable automatic whitespace stripping on string searches (default: true) config.strip_whitespace = false # PostgreSQL NULL sort ordering config.postgres_fields_sort_option = :nulls_last # or :nulls_first, :nulls_always_first, :nulls_always_last # Custom sort link arrows config.custom_arrows = { up_arrow: '', down_arrow: '', default_arrow: '' } # Disable boolean sanitization for custom scope arguments config.sanitize_custom_scope_booleans = false end ``` -------------------------------- ### URL Parameter Structure for Ransack Source: https://github.com/activerecord-hackery/ransack/wiki/Basic-Searching Demonstrates how to construct URL parameters for Ransack searches, including nested search conditions and sorting. This is useful when not using form helpers. ```plaintext /users.json?q[first_name_cont]=pete&q[last_name_cont]=jack&q[s]=created_at+desc ``` -------------------------------- ### Translate Predicate and Attribute Labels with I18n Source: https://github.com/activerecord-hackery/ransack/wiki/Form-Customization Use translation files to customize the display names for predicates and attributes in Ransack forms. Refer to the locale files in Ransack::Locale for more examples. ```yml # locales/en.yml en: ransack: asc: ascending desc: descending predicates: cont: contains not_cont: not contains start: starts with end: ends with gt: greater than lt: less than attributes: person: name: Full Name article: title: Article Title body: Main Content ``` -------------------------------- ### Run Ransack Tests with PostgreSQL or MySQL Source: https://github.com/activerecord-hackery/ransack/blob/main/CONTRIBUTING.md Configures and runs the Ransack test suite using PostgreSQL or MySQL databases. Ensure the 'ransack' database exists. ```sh DB=pg bundle exec rake spec ``` ```sh DB=mysql bundle exec rake spec ``` -------------------------------- ### Search JSONB Column Using Custom 'jcont' Predicate Source: https://github.com/activerecord-hackery/ransack/wiki/PostgreSQL-JSONB-searches Example of using the custom 'jcont' predicate to find records where a JSONB column contains a specific key-value pair. This is efficient with a GIN index. ```ruby Person.ransack(data_jcont: '{"group": "experts"}').result.to_sql ``` -------------------------------- ### Programmatic Sorting with Globalized Attributes and Joins Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/other-notes.md For programmatic sorting on globalized attributes, let Ransack establish the initial sorting joins, then add any necessary additional joins. ```ruby # Let Ransack handle the sorting joins first search = Book.ransack({ s: ['category_translations_name asc'] }) results = search.result.joins(:translations) # Or use includes for complex scenarios search = Book.ransack({ s: ['category_translations_name asc'] }) results = search.result.includes(:translations, category: :translations) ``` -------------------------------- ### Ransacker for Checking Row Existence in Another Table Source: https://github.com/activerecord-hackery/ransack/wiki/Using-Ransackers Defines a ransacker to check for the existence of a row in another table via a join. This example uses PostgreSQL syntax to return a boolean value indicating existence. ```ruby # in the model: ransacker :price_exists do |parent| # SQL syntax for PostgreSQL -- others may differ # This returns boolean true or false Arel.sql("(select exists (select 1 from prices where prices.book_id = books.id))") end ``` -------------------------------- ### Sort Link for Polymorphic Associations Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md When dealing with polymorphic associations, explicitly specify the attribute name to avoid 'uninitialized constant' errors. This example sorts by an attribute of a polymorphic association named 'xxxable' of type 'Ymodel'. ```erb <%= sort_link(@q, :xxxable_of_Ymodel_type_some_attribute, 'Attribute Name') %> ``` -------------------------------- ### Configure PostgreSQL NULLS ALWAYS FIRST Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Forces null values to always be treated as the lowest value in PostgreSQL sorting. ```ruby Ransack.configure do |c| c.postgres_fields_sort_option = :nulls_always_first end ``` -------------------------------- ### View Helper for Existence Ransacker Source: https://github.com/activerecord-hackery/ransack/wiki/Using-Ransackers Provides a Haml view helper to create a select dropdown for the `price_exists` ransacker, allowing users to filter by 'Any', 'No', or 'Yes'. ```haml %td= f.select :price_exists_true, [["Any", 2], ["No", 0], ["Yes", 1]] ``` -------------------------------- ### Interactive Rebase and Force Push Source: https://github.com/activerecord-hackery/ransack/blob/main/CONTRIBUTING.md Performs an interactive rebase on the last 10 commits for cleanup and then force pushes the changes to the remote branch. ```sh git rebase -i HEAD~10 git push -f ``` -------------------------------- ### OR Grouping in Ransack Queries Source: https://context7.com/activerecord-hackery/ransack/llms.txt By default, Ransack conditions are ANDed. Pass `m: 'or'` to group all conditions with OR logic. This can be toggled via URL parameters or applied directly in console examples. It also works across associations, automatically generating LEFT OUTER JOINs. ```ruby # controller — allow toggling OR mode from params def index @q = Artist.ransack(params[:q].try(:merge, m: 'or')) @artists = @q.result end # console example artists = Artist.ransack(name_cont: 'foo', style_cont: 'bar', m: 'or') artists.result.to_sql # => SELECT "artists".* FROM "artists" # WHERE (("artists"."name" ILIKE '%foo%' OR "artists"."style" ILIKE '%bar%')) # OR across associations (generates LEFT OUTER JOINs automatically) Artist.ransack(name_cont: 'foo', musicians_email_cont: 'bar', m: 'or').result.to_sql # => SELECT "artists".* FROM "artists" # LEFT OUTER JOIN "memberships" ON "memberships"."artist_id" = "artists"."id" # LEFT OUTER JOIN "musicians" ON "musicians"."id" = "memberships"."musician_id" # WHERE (("artists"."name" ILIKE '%foo%' OR "musicians"."email" ILIKE '%bar%')) ``` -------------------------------- ### Configure PostgreSQL NULLS FIRST Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Configures Ransack to use 'NULLS FIRST' for PostgreSQL sorting, ensuring null values appear before non-null values. ```ruby Ransack.configure do |c| c.postgres_fields_sort_option = :nulls_first end ``` -------------------------------- ### Sorting by Model Scopes Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Demonstrates how to sort by virtual fields defined as scopes in the model. The scope names should correspond to the virtual field names used in `sort_link`. ```ruby class Person < ActiveRecord::Base scope :sort_by_reverse_name_asc, lambda { order("REVERSE(name) ASC") } scope :sort_by_reverse_name_desc, lambda { order("REVERSE(name) DESC") } ... end ``` -------------------------------- ### Run Ransack Test Suite Source: https://github.com/activerecord-hackery/ransack/blob/main/CONTRIBUTING.md Executes the Ransack test suite using Rake. The default database is SQLite3. ```sh bundle exec rake spec ``` -------------------------------- ### Configure Ransack Search Key Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Change the default search parameter key from `:q` to another name, like `:query`, by setting `search_key` in an initializer. ```ruby Ransack.configure do |c| c.search_key = :query end ``` -------------------------------- ### Configure Custom Sort Arrows Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Globally customizes the sort order indicator arrows by defining HTML for up, down, and default arrows in an initializer file. ```ruby Ransack.configure do |c| c.custom_arrows = { up_arrow: '', down_arrow: 'U+02193', default_arrow: '' } end ``` -------------------------------- ### AJAX Request with Ransack Parameters Source: https://github.com/activerecord-hackery/ransack/wiki/Basic-Searching Shows how to send Ransack search parameters via an AJAX request using jQuery. The `q` object mirrors the URL parameter structure. ```javascript $.ajax({ url: "/users.json", data: { q: { first_name_cont: "pete", last_name_cont: "jack", s: "created_at desc" } }, success: function (data){ console.log(data); } }); ``` -------------------------------- ### Register Custom Ransack Predicates Source: https://context7.com/activerecord-hackery/ransack/llms.txt Configures custom search predicates in an initializer. Supports value formatting, validation, and type casting for extended search capabilities. ```ruby # config/initializers/ransack.rb ``` ```ruby Ransack.configure do |config| ``` ```ruby # Simple custom predicate with value formatting ``` ```ruby config.add_predicate 'equals_diddly', arel_predicate: 'eq', formatter: proc { |v| "#{v}-diddly" }, validator: proc { |v| v.present? }, compounds: true, type: :string, case_insensitive: false ``` ```ruby # Date equals — cast user string input and DB datetime to date ``` ```ruby config.add_predicate 'date_equals', arel_predicate: 'eq', formatter: proc { |v| v.to_date }, validator: proc { |v| v.present? }, type: :string ``` ```ruby # JSONB contains (requires ActiveRecordExtended gem) ``` ```ruby config.add_predicate 'jcont', arel_predicate: 'contains', formatter: proc { |v| JSON.parse(v) } ``` ```ruby end ``` ```ruby # Monkey-patch a custom Arel predicate not in the standard set ``` ```ruby module Arel ``` ```ruby module Predications ``` ```ruby def gteq_or_null(other) ``` ```ruby gteq(other).or(eq(nil)) ``` ```ruby end ``` ```ruby end ``` ```ruby end ``` ```ruby Ransack.configure do |config| ``` ```ruby config.add_predicate 'gteq_or_null', arel_predicate: 'gteq_or_null' ``` ```ruby end ``` -------------------------------- ### Configure Git User Information Source: https://github.com/activerecord-hackery/ransack/blob/main/CONTRIBUTING.md Sets the global Git configuration for the contributor's name and email address, which is used in commit history. ```sh git config --global user.name "Your Name" git config --global user.email "contributor@example.com" ``` -------------------------------- ### Ransack i18n Configuration for Labels Source: https://context7.com/activerecord-hackery/ransack/llms.txt Configure human-readable labels for Ransack predicates and model/attribute names using standard Rails I18n locale files. ```yaml # config/locales/en.yml en: ransack: asc: ascending desc: descending predicates: cont: contains not_cont: does not contain start: starts with end: ends with eq: equals not_eq: not equals gt: greater than lt: less than blank: is blank null: is null models: person: Passenger attributes: person: name: Full Name email: Email Address article: title: Article Title body: Main Content activerecord: attributes: namespace/article: title: AR Namespaced Title ``` -------------------------------- ### ApplicationController Search Methods Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/saving-queries.md Defines helper methods in ApplicationController to abstract search parameter handling and provide a way to clear search parameters. ```ruby class ApplicationController < ActionController::Base def search_params params[:q] end def clear_search_index if params[:search_cancel] params.delete(:search_cancel) if(!search_params.nil?) search_params.each do |key, param| search_params[key] = nil end end end end end ``` -------------------------------- ### Case-Insensitive Containment (All Values) Source: https://github.com/activerecord-hackery/ransack/wiki/Basic-Searching Use `i_cont_all` to find records where a field contains all specified substrings, ignoring case. This is useful for multi-term searches. ```ruby >> User.ransack(city_i_cont_all: %w(Grand Rapids)).result.to_sql => SELECT "users".* FROM "users" WHERE ((LOWER("users"."city") LIKE '%grand%' AND LOWER("users"."city") LIKE '%rapids%')) ``` -------------------------------- ### Index Action with Ransack Search Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/saving-queries.md This code snippet shows a typical index action in a Rails controller that initializes a Ransack search object and sets a default sort column. ```ruby def index @search = ComponentDefinition.search(search_params) # make name the default sort column @search.sorts = 'name' if @search.sorts.empty? @component_definitions = @search.result().page(params[:page]) end ``` -------------------------------- ### Ransack Built-in Predicates: Null/Blank Checks Source: https://context7.com/activerecord-hackery/ransack/llms.txt Use `_null` to check for NULL values and `_not_null` to check for non-NULL values. `_present` checks for non-NULL and non-empty string, while `_blank` checks for NULL or empty string. ```ruby # null / not_null — IS NULL / IS NOT NULL User.ransack(first_name_null: 1).result.to_sql # => SELECT "users".* FROM "users" WHERE "users"."first_name" IS NULL # present / blank — not null and not empty string User.ransack(first_name_present: '1').result.to_sql # => SELECT "users".* FROM "users" WHERE (("users"."first_name" IS NOT NULL AND "users"."first_name" != '')) ``` -------------------------------- ### Ransack Built-in Predicates: Equality Source: https://context7.com/activerecord-hackery/ransack/llms.txt Use `_eq` for exact equality and `_not_eq` for inequality. ```ruby # eq / not_eq — exact equality User.ransack(first_name_eq: 'Ryan').result.to_sql # => SELECT "users".* FROM "users" WHERE "users"."first_name" = 'Ryan' ``` -------------------------------- ### Run Specific Ransack Test File Source: https://github.com/activerecord-hackery/ransack/blob/main/CONTRIBUTING.md Executes the Ransack test suite for a particular file. Replace `` with the actual file path. ```sh bundle exec rspec spec/ransack/search_spec.rb ``` -------------------------------- ### Polymorphic Search with Namespaced Models Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/polymorphic-search.md Shows how to perform polymorphic searches when the associated model is namespaced. Use a quoted string with Ruby module notation for the type. ```ruby Location.ransack('locatable_of_Residences::House_type_number_eq' => 100).result ``` -------------------------------- ### Release to RubyGems Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/release_process.md Commands to build and release the Ransack gem to RubyGems. Ensure you are signed in to RubyGems. ```bash gem signin rake build rake release ``` -------------------------------- ### Basic Sort Link Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Generates a sortable link for the specified attribute. Clicking this link will toggle the sort order for the 'name' attribute. ```erb <%= sort_link(@q, :name) %> ``` -------------------------------- ### Ransack Search: Match Exact Key Combinations Source: https://github.com/activerecord-hackery/ransack/wiki/How-to-search-on-ActsAsTaggableOn-fields Use `_eq` predicate to match exact combinations of tags. This is useful when searching for a specific set of tags and no others. ```erb <%= f.text_field :projects_name_eq %> ``` -------------------------------- ### Add Sorting Links to View Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/sorting.md Use the `sort_link` helper within your table headers to create clickable links for sorting. This requires the Ransack search object `@q` to be available in the view. ```erb <% @posts.each do |post| %> <% end %>
<%= sort_link(@q, :title, "Title") %> <%= sort_link(@q, :category, "Category") %> <%= sort_link(@q, :created_at, "Created at") %>
<%= post.title %> <%= post.category %> <%= post.created_at.to_s(:long) %>
``` -------------------------------- ### Programmatic Sorting with Globalized Attributes Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/i18n.md When sorting programmatically on translated attributes of associations, let Ransack handle the initial joins. Add any additional required joins afterward or use `includes` to ensure translations are loaded. ```ruby # Instead of joining translations first, let Ransack handle the joins: search = Book.ransack({ s: ['category_translations_name asc'] }) results = search.result.joins(:translations) # Or use the includes method to ensure all necessary translations are loaded: search = Book.ransack({ s: ['category_translations_name asc'] }) results = search.result.includes(:translations, category: :translations) # For more complex scenarios, you can manually specify the joins: search = Book.ransack({ s: ['category_translations_name asc'] }) results = search.result .joins(:translations) .joins(category: :translations) ``` -------------------------------- ### Configure PostgreSQL NULLS LAST Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Configures Ransack to use 'NULLS LAST' for PostgreSQL sorting, ensuring null values appear after non-null values. ```ruby Ransack.configure do |c| c.postgres_fields_sort_option = :nulls_last end ``` -------------------------------- ### Run Single Test in Ransack File Source: https://github.com/activerecord-hackery/ransack/blob/main/CONTRIBUTING.md Runs a specific test case within a Ransack test file. Use the `-e` flag followed by the test name. ```sh bundle exec rspec spec/ransack/search_spec.rb -e "accepts a context option" ``` -------------------------------- ### Use Bleeding Edge Ransack from GitHub Source: https://github.com/activerecord-hackery/ransack/blob/main/README.md To use the latest updates not yet published to RubyGems, specify the GitHub repository and branch in your Gemfile. ```ruby gem 'ransack', :github => 'activerecord-hackery/ransack', :branch => 'main' ``` -------------------------------- ### Set Multiple Default Sort Orders in Controller Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/sorting.md Configure multiple default sort orders by passing an array of sort strings to the `sorts` attribute. Ransack will apply them in the order provided. ```ruby class PostsController < ActionController::Base def index @q = Post.ransack(params[:q]) @q.sorts = ['title asc', 'created_at desc'] if @q.sorts.empty? @posts = @q.result(distinct: true) end end ``` -------------------------------- ### Sort Link with Multiple Default Orders Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Configures sorting by multiple fields with specific default orders. Initially, 'last_name' will be sorted ascending and 'first_name' descending. ```erb <%= sort_link(@q, :last_name, %i(last_name first_name), default_order: { last_name: 'asc', first_name: 'desc' }) %> ``` -------------------------------- ### Set Default Multiple Sort Orders in Controller Source: https://github.com/activerecord-hackery/ransack/wiki/Sorting-in-the-Controller Configure multiple default sort fields and orders if no sorts are already specified. This allows for more complex default sorting logic. ```ruby @search = Post.ransack(params[:q]) @search.sorts = ['name asc', 'created_at desc'] if @search.sorts.empty? @posts = @search.result.paginate(page: params[:page], per_page: 20) ``` -------------------------------- ### Generated SQL for Merged Searches Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/merging-searches.md This SQL demonstrates how the Ransack gem constructs a query to find records matching multiple, potentially complex, conditions by using joins and an OR clause. ```sql SELECT "people".* FROM "people" LEFT OUTER JOIN "people" "parents_people" ON "parents_people"."id" = "people"."parent_id" LEFT OUTER JOIN "people" "children_people" ON "children_people"."parent_id" = "people"."id" WHERE ( ("parents_people"."name" = 'A' OR "children_people"."name" = 'B') ) ORDER BY "people"."id" DESC ``` -------------------------------- ### Ransack Built-in Predicates: Numeric Comparisons Source: https://context7.com/activerecord-hackery/ransack/llms.txt Use `_lt` (less than), `_lteq` (less than or equal to), `_gt` (greater than), and `_gteq` (greater than or equal to) for numeric comparisons. ```ruby # lt / lteq / gt / gteq — numeric comparisons User.ransack(age_lt: 25).result.to_sql # => SELECT "users".* FROM "users" WHERE ("users"."age" < 25) User.ransack(age_lteq: 25).result.to_sql # => SELECT "users".* FROM "users" WHERE ("users"."age" <= 25) ``` -------------------------------- ### Ransacker for Querying Associated Model by Name Source: https://github.com/activerecord-hackery/ransack/wiki/Using-Ransackers Demonstrates how to query a `SalesAccount` model based on the name of its associated `sales_rep` user. This requires joining the `sales_rep` association. ```ruby # in the model: class SalesAccount < ActiveRecord::Base belongs_to :user belongs_to :sales_rep, class_name: :User # in the controller: # The line below would lead to errors thrown later if not for the # "joins(:sales_reps)". @q = SalesAccount.includes(:user).joins(:sales_rep).ransack(params[:q]) @sales_accounts = @q.result(distinct: true) ``` -------------------------------- ### Add Controller Action for Advanced Search Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/advanced-mode.md Implement a 'search' action in your controller that calls the 'index' method and then renders the 'index' view. This action is invoked by the custom route defined for advanced search. ```ruby def search index render :index end ``` -------------------------------- ### Configure PostgreSQL NULLS ALWAYS LAST Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Forces null values to always be treated as the highest value in PostgreSQL sorting. ```ruby Ransack.configure do |c| c.postgres_fields_sort_option = :nulls_always_last end ``` -------------------------------- ### Ransack Built-in Predicates: String Contains Source: https://context7.com/activerecord-hackery/ransack/llms.txt Use `_cont` for LIKE '%value%' searches and `_i_cont` for case-insensitive LIKE searches using LOWER(). ```ruby # cont / not_cont — LIKE '%value%' User.ransack(first_name_cont: 'Rya').result.to_sql # => SELECT "users".* FROM "users" WHERE ("users"."first_name" LIKE '%Rya%') # i_cont — case-insensitive LIKE (uses LOWER()) User.ransack(first_name_i_cont: 'rya').result.to_sql # => SELECT "users".* FROM "users" WHERE (LOWER("users"."first_name") LIKE '%rya%') ``` -------------------------------- ### Generate Sort URL with Multiple Default Orders Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/getting-started/simple-mode.md Generates a sort URL with multiple default sort orders specified, mirroring the behavior of `sort_link` with multiple default orders. ```erb <%= sort_url(@q, :last_name, %i(last_name first_name), default_order: { last_name: 'asc', first_name: 'desc' }) %> ``` -------------------------------- ### Ransack Built-in Predicates: Raw LIKE Pattern Source: https://context7.com/activerecord-hackery/ransack/llms.txt Use `_matches` for raw LIKE pattern matching without auto-added wildcards, and `_does_not_match` for the inverse. ```ruby # matches / does_not_match — raw LIKE pattern (no auto-wildcards) User.ransack(first_name_matches: 'Ryan').result.to_sql # => SELECT "users".* FROM "users" WHERE ("users"."first_name" LIKE 'Ryan') ``` -------------------------------- ### Handle Distinct Selects with Group and Includes (PostgreSQL) Source: https://github.com/activerecord-hackery/ransack/blob/main/docs/docs/going-further/other-notes.md For PostgreSQL, an alternative to `distinct: true` is to use `.group` on the primary key along with `.includes` to avoid duplicate rows. ```ruby def index @q = Person.ransack(params[:q]) @people = @q.result .group('persons.id') .includes(:articles) .page(params[:page]) end ```