{"record":{"id":"43a32d15b1aabe22","repo":"railsadminteam/rails_admin","slug":"unsupported-sort-value-options-sort","errorCode":null,"errorMessage":"Unsupported sort value: #{options[:sort]}","messagePattern":"Unsupported sort value: #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/rails_admin/adapters/active_record.rb","lineNumber":171,"sourceCode":"        if primary_key.is_a? Array\n          options[:bulk_ids].map { |id| primary_key_scope(scope, id) }.reduce(&:or)\n        else\n          scope.where(primary_key => options[:bulk_ids])\n        end\n      end\n\n      def sort_scope(scope, options)\n        direction = options[:sort_reverse] ? :asc : :desc\n        case options[:sort]\n        when String, Symbol\n          scope.reorder(\"#{options[:sort]} #{direction}\")\n        when Array\n          scope.reorder(options[:sort].zip(Array.new(options[:sort].size) { direction }).to_h)\n        when Hash\n          scope.reorder(options[:sort].map { |table_name, column| \"#{table_name}.#{column}\" }.\n            zip(Array.new(options[:sort].size) { direction }).to_h)\n        else\n          raise ArgumentError.new(\"Unsupported sort value: #{options[:sort]}\")\n        end\n      end\n\n      class WhereBuilder\n        def initialize(scope)\n          @statements = []\n          @values = []\n          @tables = []\n          @scope = scope\n        end\n\n        def add(field, value, operator)\n          field.searchable_columns.flatten.each do |column_infos|\n            statement, value1, value2 = StatementBuilder.new(column_infos[:column], column_infos[:type], value, operator, @scope.connection.adapter_name).to_statement\n            @statements << statement if statement.present?\n            @values << value1 unless value1.nil?\n            @values << value2 unless value2.nil?\n            table, column = column_infos[:column].split('.')","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/railsadminteam/rails_admin/blob/0690a5e62f8d99bc00495a3754f5189b23124387/lib/rails_admin/adapters/active_record.rb#L153-L189","documentation":"RailsAdmin's ActiveRecord adapter builds the ORDER BY clause in sort_scope (lib/rails_admin/adapters/active_record.rb:160). options[:sort] must be a String/Symbol column name, an Array of columns, or a one-level Hash of {table_name => column}; any other class raises ArgumentError before SQL is generated. The value normally comes from MainController#get_sort_hash (app/controllers/rails_admin/main_controller.rb:66), which uses the matched field's sort_column (a String) or falls back to the model's list.sort_by configuration.","triggerScenarios":"Calling AbstractModel#all (or list_entries) with options[:sort] that is not String/Symbol/Array/Hash — e.g. abstract_model.all(sort: 123) or sort: User.arel_table[:name].asc (an Arel node). Or configuring `list { sort_by <non-column-object> }`, since get_sort_hash falls back to list.sort_by verbatim when params[:sort] does not match a field name. A Hash deeper than one level (nested hashes as values) also lands in the unsupported branch behavior.","commonSituations":"Custom code or specs that call the adapter/all API directly with an old or hand-built options hash; a model config where sort_by is assigned something other than a column name (Proc result, Integer, Arel node); upgrading an app whose sort_by was tolerated by an older adapter version; passing a nested sortable Hash instead of the flat {table => column} form.","solutions":["If the value comes from config, make list.sort_by a plain column name: `list { sort_by :created_at }` — or a String/Symbol like 'players.name', an Array [:last_name, :first_name], or a flat Hash {players: :name} for association sorting.","If you call abstract_model.all / the adapter yourself, pass only String, Symbol, Array of column names, or a one-level {table => column} Hash as the :sort value.","For computed sorting (Arel/SQL expressions), pass the raw SQL string form that the String branch accepts, or wrap the call and apply reorder() yourself on the returned scope.","If the sort value can be user-supplied, validate its class before it reaches the adapter (see defense) instead of letting ArgumentError surface as a 500."],"exampleFix":"# before (raises ArgumentError: Unsupported sort value)\nRailsAdmin.config do |config|\n  config.model Player do\n    list { sort_by 123 }\n  end\nend\nabstract_model.all(sort: Player.arel_table[:name].asc)\n\n# after\nRailsAdmin.config do |config|\n  config.model Player do\n    list { sort_by :created_at }   # String, Symbol, Array, or {table: :column} Hash\n  end\nend\nabstract_model.all(sort: 'players.name')","handlingStrategy":"type-guard","validationCode":"# Before calling the adapter / building list options\nsort = options[:sort]\nunless sort.nil? || [String, Symbol, Array, Hash].any? { |k| sort.is_a?(k) }\n  raise ArgumentError, \"options[:sort] must be String/Symbol/Array/Hash, got #{sort.class}\"\nend\n# also reject nested hashes: only {table => column} one level deep is valid\noptions[:sort] = nil if sort.is_a?(Hash) && sort.values.any? { |v| v.is_a?(Hash) }","typeGuard":"# Ruby type guard mirroring sort_scope's case statement (active_record.rb:162)\nvalid_sort_value = lambda do |v|\n  v.is_a?(String) || v.is_a?(Symbol) ||\n    (v.is_a?(Array) && v.all? { |c| c.is_a?(String) || c.is_a?(Symbol) }) ||\n    (v.is_a?(Hash) && v.values.all? { |c| c.is_a?(String) || c.is_a?(Symbol) })\nend\nvalid_sort_value.call(options[:sort]) # => true/false","tryCatchPattern":"begin\n  scope = abstract_model.all(sort: requested_sort, sort_reverse: params[:sort_reverse])\nrescue ArgumentError => e\n  Rails.logger.warn(\"RailsAdmin sort rejected (#{e.message}); falling back to unsorted scope\")\n  scope = abstract_model.all # retry without sort rather than 500ing the index page\nend","preventionTips":["Keep list.sort_by to a literal column name (Symbol/String) in config; never assign computed objects or Integers.","If you call abstract_model.all directly, treat its options hash as a typed API — only String/Symbol/Array/{table=>column} Hash for :sort.","Add a one-line spec per model asserting model_config.list.sort_by is one of the supported classes, so a bad config fails in CI not production.","Cover admin index pages with a request spec that toggles params[:sort] to catch sorting regressions before deploy."],"tags":["rails-admin","activerecord","sorting","argument-error","ruby","configuration"],"backgroundTag":"invalid-argument-type","analyzedSha":"0690a5e62f8d99bc00495a3754f5189b23124387","analyzedAt":"2026-08-21T18:31:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}