{"record":{"id":"2f08d35b8036f5f6","repo":"activerecord-hackery/ransack","slug":"a-context-is-required-to-translate-associations","errorCode":null,"errorMessage":"A context is required to translate associations","messagePattern":"A context is required to translate associations","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/ransack/translate.rb","lineNumber":58,"sourceCode":"\n        interpolations = {\n          attributes: translated_names.join(\" #{Translate.word(combinator)} \")\n        }\n\n        if predicate\n          defaults << \"%{attributes} %{predicate}\".freeze\n          interpolations[:predicate] = Translate.predicate(predicate)\n        else\n          defaults << \"%{attributes}\".freeze\n        end\n\n        options.reverse_merge! count: 1, default: defaults\n        I18n.translate(defaults.shift, **options.merge(interpolations))\n      end\n\n      def association(key, options = {})\n        unless context = options.delete(:context)\n          raise ArgumentError, \"A context is required to translate associations\"\n        end\n\n        defaults =\n          if key.blank?\n            [:\"ransack.models.#{i18n_key(context.klass)}\",\n             :\"#{context.klass.i18n_scope}.models.#{i18n_key(context.klass)}\"]\n          else\n            [:\"ransack.associations.#{i18n_key(context.klass)}.#{key}\"]\n          end\n        defaults << context.traverse(key).model_name.human\n        options = { count: 1, default: defaults }\n        I18n.translate(defaults.shift, **options)\n      end\n\n      private\n\n      def attribute_name(context, name, include_associations = nil)\n        @context, @name = context, name","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/activerecord-hackery/ransack/blob/e82f6bab3956c5597e7debbefa218d9e94e58ceb/lib/ransack/translate.rb#L40-L76","documentation":"Ransack::Translate.association resolves a human name for an association key (or the model itself when key is blank) via I18n ('ransack.associations.<model>.<key>', falling back to context.traverse(key).model_name.human). Traversal needs the search context's base class, so options[:context] is mandatory; omitting it raises this ArgumentError.","triggerScenarios":"Ransack::Translate.association(:articles) with no context option; custom view helpers that call Translate.association while forwarding an options hash that dropped :context; translating nested association labels (e.g. 'author_articles_title') outside a real search.","commonSituations":"Custom label/partial code extracted from Ransack forms that calls the Translate module directly; I18n-related specs; refactors where the options hash is rebuilt and :context is lost.","solutions":["Pass the context: Ransack::Translate.association(:articles, context: @q.context)","Use the search-level API instead: @q.translate(:articles) or form builder labels, which supply the context for you","Ensure custom helpers forward the full options hash including :context when delegating to Translate"],"exampleFix":"# before\nRansack::Translate.association(:articles)\n# => ArgumentError: A context is required to translate associations\n\n# after\nsearch = Person.ransack\nRansack::Translate.association(:articles, context: search.context)","handlingStrategy":"validation","validationCode":"search = Person.ransack\nRansack::Translate.association(:articles, context: search.context)","typeGuard":"def translatable_association_call?(key, options)\n  options.key?(:context) && options[:context].respond_to?(:traverse)\nend","tryCatchPattern":null,"preventionTips":["Supply context: search.context for every direct Translate.association call","Remember the association key must be traversable from the context's base class, or traverse raises separately","Use the built-in label/i18n paths first; drop to Translate.* only when you must, and always with a context"],"tags":["ruby","rails","ransack","i18n","translate","associations","argumenterror"],"backgroundTag":"missing-required-option","analyzedSha":"e82f6bab3956c5597e7debbefa218d9e94e58ceb","analyzedAt":"2026-08-21T19:30:23.639Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}