activerecord-hackery/ransack · error · TypeError
First argument must be a Ransack::Search!
Error message
First argument must be a Ransack::Search!
What it means
The sort_link view helper raises a TypeError when, after unwrapping an optional [routing_proxy, search] array, its first effective argument is not a Ransack::Search instance. sort_link reads the search's context (klass, sorts) to build the column-header link, so any other object (model instance, relation, nil) is rejected up front.
Source
Thrown at lib/ransack/helpers/form_helper.rb:68
html_options = build_html_options(search, options, method).merge(turbo_options)
finalize_form_options(options, html_options)
form_for(record, options, &proc)
end
# +sort_link+
#
# <%= sort_link(@q, :name, [:name, 'kind ASC'], 'Player Name') %>
#
# You can also use a block:
#
# <%= sort_link(@q, :name, [:name, 'kind ASC']) do %>
# <strong>Player Name</strong>
# <% end %>
#
def sort_link(search_object, attribute, *args, &block)
search, routing_proxy = extract_search_and_routing_proxy(search_object)
unless Search === search
raise TypeError, 'First argument must be a Ransack::Search!'
end
args[args.first.is_a?(Array) ? 1 : 0, 0] = capture(&block) if block_given?
s = SortLink.new(search, attribute, args, params, &block)
link_to(s.name, url(routing_proxy, s.url_options), s.html_options(args))
end
# +sort_url+
# <%= sort_url(@q, :created_at, default_order: :desc) %>
#
def sort_url(search_object, attribute, *args)
search, routing_proxy = extract_search_and_routing_proxy(search_object)
unless Search === search
raise TypeError, 'First argument must be a Ransack::Search!'
end
s = SortLink.new(search, attribute, args, params)
url(routing_proxy, s.url_options)
end
View on GitHub (pinned to e82f6bab39)
Solutions
- Set @q = Person.ransack(params[:q]) in the controller and call sort_link(@q, :name)
- If you use the array form for routing proxies, keep the search object as the second element: sort_link([:admin, @q], :name)
- If @q can be nil (e.g. non-GET renders), initialize a default: @q ||= Person.ransack
Example fix
# controller # before def index @people = Person.all end # after def index @q = Person.ransack(params[:q]) @people = @q.result end # view (unchanged) <%= sort_link(@q, :name, 'Person Name') %>
Defensive patterns
Strategy: type-guard
Validate before calling
# in the controller, guarantee the instance var exists before render: @q = Person.ransack(params[:q]) if @q.nil?
Type guard
def ransack_search?(obj) obj.is_a?(Ransack::Search) end # view: <%= sort_link(@q, :name) if ransack_search?(@q) %>
Prevention
- Always assign @q in the controller action that renders the sortable table
- Name the variable @q consistently — sort_link(@people, ...) is the classic copy-paste mistake
- For the array/proxy form, verify the LAST element is the search: [:admin, @q]
When it happens
Trigger: sort_link(@person, :name) where @person is a record or relation; sort_link(params[:q], :name) (raw params hash); forgetting @q = Person.ransack(params[:q]) in the controller; passing a routing-proxy array whose second element is not the search, e.g. [admin_proxy, @person].
Common situations: New Ransack installations where the controller still passes a relation to the view; refactoring views and dropping the @q assignment; using sort_link in a partial that receives the wrong local variable; passing an array form incorrectly for engines/admin namespaces.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- attribute_select must be called inside a search FormBuilder!
- No Ransack::Search object was provided to #{method_name}!
- #{type} cannot be converted to an ARel join type
- #{value} cannot be converted to a Class
- Don't know how to klassify #{obj}
AI-assisted analysis of activerecord-hackery/ransack@e82f6bab39 (2026-08-21).
Data as JSON: /api/errors/1ef60de8e6679ce0.
Report an issue: GitHub.