activerecord-hackery/ransack · error · ArgumentError

attribute_select must be called inside a search FormBuilder!

Error message

attribute_select must be called inside a search FormBuilder!

What it means

Ransack's FormBuilder#attribute_select (and sort_select, which delegates to it) requires the form's underlying object to be a Ransack::Search — detected by responding to #context. If you use these helpers inside a plain form_for(@record) form, the object is an AR model that does not respond to :context, and this ArgumentError is raised.

Source

Thrown at lib/ransack/helpers/form_builder.rb:51

        i18n = options[:i18n] || {}
        text ||= object.translate(
          method, i18n.reverse_merge(include_associations: true)
          ) if object.respond_to? :translate
        super(method, text, options, &block)
      end

      def submit(value = nil, options = {})
        value, options = nil, value if value.is_a?(Hash)
        value ||= Translate.word(:search).titleize
        super(value, options)
      end

      def attribute_select(options = nil, html_options = nil, action = nil)
        options ||= {}
        html_options ||= {}
        action ||= Constants::SEARCH
        default = options.delete(:default)
        raise ArgumentError, formbuilder_error_message(
          "#{action}_select") unless object.respond_to?(:context)
        options[:include_blank] = true unless options.has_key?(:include_blank)
        bases = [''.freeze].freeze + association_array(options[:associations])
        if bases.size > 1
          collection = attribute_collection_for_bases(action, bases)
          object.name ||= default if can_use_default?(
            default, :name, mapped_values(collection.flatten(2))
            )
          template_grouped_collection_select(collection, options, html_options)
        else
          collection = collection_for_base(action, bases.first)
          object.name ||= default if can_use_default?(
            default, :name, mapped_values(collection)
            )
          template_collection_select(:name, collection, options, html_options)
        end
      end

View on GitHub (pinned to e82f6bab39)

Solutions

  1. Build a search object in the controller: @q = Article.ransack(params[:q])
  2. Use search_form_for @q do |f| (Ransack's helper) so the builder object is the search, then f.attribute_select works
  3. If the form must stay a plain form_for, replace attribute_select with your own collection_select over Article.ransackable_attributes

Example fix

# controller
before: @article = Article.new
after:  @q = Article.ransack(params[:q])

# view
<!-- before -->
<%= form_for @article do |f| %>
  <%= f.attribute_select %>
<% end %>

<!-- after -->
<%= search_form_for @q do |f| %>
  <%= f.attribute_select %>
<% end %>
Defensive patterns

Strategy: type-guard

Type guard

def search_form_builder?(builder)
  builder.object.respond_to?(:context) # true only for Ransack::Search objects
end

Prevention

When it happens

Trigger: <%= form_for @article do |f| %> <%= f.attribute_select %> — attribute_select, f.sort_select, or any 'search_select'/'sort_select' action variant called on a builder bound to a model instance or relation instead of a Ransack::Search.

Common situations: Copy-pasting a Ransack view snippet into an existing form_for block; forgetting to build @q in the controller; using simple_form_for/form_with with a record instead of search_form_for with a search object.

Related errors


AI-assisted analysis of activerecord-hackery/ransack@e82f6bab39 (2026-08-21). Data as JSON: /api/errors/a04411a9d7f890e4. Report an issue: GitHub.