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字符串拼接语法错误:
with_owner_or_assigned_branch、left_join_branch等scope的SQL字符串中,#(井号加空格)后面的换行导致Ruby将后续内容识别为注释,使得SQL语句不完整,进而引发参数解析错误。- 直接使用字符串插值拼接SQL不仅存在语法风险,还可能导致SQL注入漏洞。
修复方案
修复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) }优化排序scope,使用Arel语法避免字符串错误
将ordered_by_category改为使用Arel语法,更安全且不易出错:scope :ordered_by_category, -> { order(Category.arel_table[:name].asc) }确保模型定义完整
检查Service模型末尾是否有end,用户提供的代码中缺失该闭合语句,需补充。
验证修复
修改后重新调用控制器中的查询链,参数数量错误会消失,同时SQL语句会正确生成,实现按分类名称排序的功能。
内容的提问来源于stack exchange,提问作者Iventura
相关产品推荐
相关产品推荐

