activerecord-hackery/ransack · error · ArgumentError

A context is required to translate attributes

Error message

A context is required to translate attributes

What it means

Ransack::Translate.attribute resolves human-readable names for an attribute (or attribute+predicate) key via I18n, using the search context's model class and its ancestors to build translation lookup keys ('ransack.attributes.<model>.<key>', activerecord.attributes..., etc.). It requires the calling search's context to be passed in options[:context]; without it there is no model to translate against and this ArgumentError is raised.

Source

Thrown at lib/ransack/translate.rb:20

I18n.load_path += Dir[
  File.join(File.dirname(__FILE__), 'locale'.freeze, '*.yml'.freeze)
]

module Ransack
  module Translate
    class << self
      def word(key, options = {})
        I18n.translate(:"ransack.#{key}", default: key.to_s)
      end

      def predicate(key, options = {})
        I18n.translate(:"ransack.predicates.#{key}", default: key.to_s)
      end

      def attribute(key, options = {})
        unless context = options.delete(:context)
          raise ArgumentError, "A context is required to translate attributes"
        end

        original_name = key.to_s
        base_class = context.klass
        base_ancestors = base_class.ancestors.select {
          |x| x.respond_to?(:model_name)
        }
        attributes_str = original_name.dup # will be modified by ⬇
        predicate = Predicate.detect_and_strip_from_string!(attributes_str)
        attribute_names = attributes_str.split(/_and_|_or_/)
        combinator = attributes_str =~ /_and_/ ? :and : :or
        defaults = base_ancestors.map do |klass|
          "ransack.attributes.#{i18n_key(klass)}.#{original_name}".to_sym
        end
        defaults << options.delete(:default) if options[:default]

        translated_names = attribute_names.map do |name|
          attribute_name(context, name, options[:include_associations])

View on GitHub (pinned to e82f6bab39)

Solutions

  1. Pass the search context: Ransack::Translate.attribute('name_cont', context: @q.context)
  2. Prefer the higher-level API: @q.translate('name_cont') or the form builder's label, which forward the context automatically
  3. In specs, build a real search first: search = Person.ransack(name_cont: 'x'); use search.context

Example fix

# before
Ransack::Translate.attribute('name_cont')
# => ArgumentError: A context is required to translate attributes

# after
search = Person.ransack(name_cont: 'x')
Ransack::Translate.attribute('name_cont', context: search.context)
Defensive patterns

Strategy: validation

Validate before calling

search = Person.ransack(name_cont: 'x')
opts = { context: search.context }.merge(user_opts)
Ransack::Translate.attribute('name_cont', opts)

Type guard

def translatable_attribute_call?(key, options)
  options.key?(:context) && options[:context].respond_to?(:klass)
end

Prevention

When it happens

Trigger: Calling Ransack::Translate.attribute('name_cont') directly with no options; calling search.base.conditions.first.attributes.first.translate(key, options) with options that omit :context (the Grouping#translate path merges context: context, but a custom call may not); helper code that copies the translate API without forwarding the context.

Common situations: Writing custom label helpers or decorators that use Translate.attribute for consistent I18n; refactoring view code and losing the context: keyword; testing translation logic in isolation without constructing a search first.

Related errors


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