You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails 7.1.3中Order报错:参数数量错误(给定1,预期0)

问题排查:按分类名称排序Scope时出现参数数量错误

我在Rails 7.1.3的Service模型中创建了一个按categories.name排序的scope,Category是存储服务分类名称的模型,期望实现按分类名字段排序,但执行时始终报错:wrong number of arguments (given 1, expected 0)。尝试了多种MySQL order调用方式,问题依旧。


相关代码

Service模型代码

class Service < ApplicationRecord
  before_save :delete_photo, if: ->{ remove_photo == "1" && photo.attached? }

  attr_accessor :remove_photo

  belongs_to :company
  belongs_to :branch, optional: true
  belongs_to :family
  belongs_to :subfamily
  belongs_to :gender_type, optional: true
  belongs_to :category, optional: true
  belongs_to :service_location, optional: true
  belongs_to :base_service, class_name: 'Service', optional: true
  has_many :additional_features, class_name: 'ServiceAdditionalFeature', dependent: :destroy
  has_and_belongs_to_many :branches
  has_and_belongs_to_many :employees
  has_one_attached :photo
  has_one_attached :video

  validate :photo_format
  validate :video_format

  after_create :set_sequence_number_after_create

  scope :with_company, ->(company) { where company: company }
  scope :with_branch, ->(branch) { where branch: branch }
  scope :with_owner_or_assigned_branch, ->(branch) { joins("LEFT 
  JOIN branches_services ON branches_services.service_id = 
  services.base_service_id AND branches_services.branch_id = # 
 {branch.present? && branch.id.present? ? branch.id : -1}")
                                                
.where("IFNULL(services.branch_id, -1) = #{branch.present? && 
branch.id.present? ? branch.id : -1} AND 
(services.base_service_id IS NULL OR 
branches_services.service_id IS NOT NULL)") }

scope :left_join_branch, ->(branch) { joins("LEFT JOIN 
branches_services ON branches_services.service_id = services.id 
AND branches_services.branch_id = #{branch.present? && 
branch.id.present? ? branch.id : -1}").select("services.*, 
IF(branches_services.branch_id IS NOT NULL, 1, 0) AS 
is_selected") }

scope :inner_join_employee, ->(employee) { 
joins(:employees).where(employees: { id: employee }).distinct }
scope :left_join_employee, ->(employee) { joins("LEFT JOIN 
employees_services ON employees_services.service_id = 
services.id AND employees_services.employee_id = # 
{employee.present? ? employee.id : -1}").select("services.*, 
IF(employees_services.employee_id IS NOT NULL, 1, 0) AS 
is_selected") }
scope :with_gender_type, ->(gender_type) { where("(# 
{gender_type} = 3 AND gender_type_id IS NULL) OR gender_type_id 
= #{gender_type}") }
scope :with_category, ->(category) { where category: category }
scope :ordered, -> { order recurrent: :desc }
scope :inner_join_subfamily, -> { 
joins(:family).joins(:subfamily).select("services.*, 
CONCAT(IFNULL(CONCAT(services.internal_reference_code, ' - '), 
''), services.name) AS fullname, families.id AS family_id, 
families.name AS family_name, subfamilies.id AS subfamily_id, 
subfamilies.name AS subfamily_name" ) }


  scope :left_join_category, -> { joins("LEFT JOIN categories ON categories.id = services.category_id").select("services.*, CONCAT(IFNULL(CONCAT(services.internal_reference_code, ' - '), ''), services.name) AS fullname, IFNULL(categories.id,  -1) AS category_id, IFNULL(categories.name, '--') AS category_name" ) }

  scope :ordered_by_subfamily, -> { order("families.name ASC, subfamilies.name ASC, CONCAT(IFNULL(CONCAT(services.internal_reference_code, ' - '), ''), services.name) ASC") }

  scope :ordered_by_category, -> { order("categories.name ASC") }

  scope :ordered_by_service, -> { order("CONCAT(IFNULL(CONCAT(services.internal_reference_code, ' - '), ''), services.name) ASC") }
end

控制器调用代码

def set_services_by_company
  @services_categories = Hash.new

  services = Service.with_company(@user.company_default).with_branch(nil).left_join_category.left_join_branch(@branch).ordered_by_category
end

问题原因

核心问题出在scope中的SQL字符串拼接语法错误:

  1. with_owner_or_assigned_branch、left_join_branch等scope的SQL字符串中,# (井号加空格)后面的换行导致Ruby将后续内容识别为注释,使得SQL语句不完整,进而引发参数解析错误。
  2. 直接使用字符串插值拼接SQL不仅存在语法风险,还可能导致SQL注入漏洞。

修复方案

  1. 修复SQL字符串拼接,改用参数占位符
    将所有包含字符串插值的scope改为使用Rails的参数占位符(?),避免注释和语法错误,同时提升安全性:

    # 修复with_owner_or_assigned_branch
    scope :with_owner_or_assigned_branch, ->(branch) { 
      branch_id = branch&.id || -1
      joins("LEFT JOIN branches_services ON branches_services.service_id = services.base_service_id AND branches_services.branch_id = ?", branch_id)
        .where("IFNULL(services.branch_id, -1) = ? AND (services.base_service_id IS NULL OR branches_services.service_id IS NOT NULL)", branch_id)
    }
    
    # 修复left_join_branch
    scope :left_join_branch, ->(branch) { 
      branch_id = branch&.id || -1
      joins("LEFT JOIN branches_services ON branches_services.service_id = services.id AND branches_services.branch_id = ?", branch_id)
        .select("services.*, IF(branches_services.branch_id IS NOT NULL, 1, 0) AS is_selected")
    }
    
    # 修复left_join_employee
    scope :left_join_employee, ->(employee) { 
      employee_id = employee&.id || -1
      joins("LEFT JOIN employees_services ON employees_services.service_id = services.id AND employees_services.employee_id = ?", employee_id)
        .select("services.*, IF(employees_services.employee_id IS NOT NULL, 1, 0) AS is_selected")
    }
    
    # 修复with_gender_type
    scope :with_gender_type, ->(gender_type) { 
      where("(? = 3 AND gender_type_id IS NULL) OR gender_type_id = ?", gender_type, gender_type)
    }
    
  2. 优化排序scope,使用Arel语法避免字符串错误
    将ordered_by_category改为使用Arel语法,更安全且不易出错:

    scope :ordered_by_category, -> { 
      order(Category.arel_table[:name].asc)
    }
    
  3. 确保模型定义完整
    检查Service模型末尾是否有end,用户提供的代码中缺失该闭合语句,需补充。


验证修复

修改后重新调用控制器中的查询链,参数数量错误会消失,同时SQL语句会正确生成,实现按分类名称排序的功能。

内容的提问来源于stack exchange,提问作者Iventura

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 21:52:32