Rails GraphQL嵌套类型查询:分类关联鞋子排序失效与参数报错问题
实现分类关联鞋子的自定义排序方案
要解决这个问题,核心是给CategoryType的shoes字段显式添加排序参数,并在字段的解析逻辑中根据参数处理排序。以下是具体实现步骤:
1. 定义排序枚举(推荐,保证参数合法性)
先创建一个枚举类型,限定允许的排序选项,避免非法参数传入:
module Types class ShoeSortEnum < Types::BaseEnum value "PRICE_ASC", description: "按价格升序排列" value "PRICE_DESC", description: "按价格降序排列" value "NAME_ASC", description: "按名称升序排列" value "NAME_DESC", description: "按名称降序排列" value "CREATED_AT_ASC", description: "按创建时间升序排列" value "CREATED_AT_DESC", description: "按创建时间降序排列" end end
2. 给shoes字段添加排序参数并实现解析逻辑
在CategoryType中,为shoes字段添加order_by参数,并在解析方法中根据参数生成排序条件:
module Types class CategoryType < Types::BaseObject field :id, ID, null: false field :name, String, null: false # 为shoes字段添加order_by参数,默认按创建时间降序 field :shoes, [Types::ShoeType], null: false do argument :order_by, Types::ShoeSortEnum, required: false, default_value: "CREATED_AT_DESC" end def shoes(order_by:) # 用Arel构建排序条件,避免SQL注入风险 shoe_table = Shoe.arel_table sort_clause = case order_by when "PRICE_ASC" then shoe_table[:price].asc when "PRICE_DESC" then shoe_table[:price].desc when "NAME_ASC" then shoe_table[:name].asc when "NAME_DESC" then shoe_table[:name].desc when "CREATED_AT_ASC" then shoe_table[:created_at].asc when "CREATED_AT_DESC" then shoe_table[:created_at].desc else shoe_table[:created_at].desc end # 对当前分类的鞋子应用排序 object.shoes.order(sort_clause) end end end
3. 测试查询示例
现在可以在GraphQL查询中指定排序规则:
query { category(id: 1) { id name shoes(orderBy: PRICE_ASC) { id name price } } }
替代方案:拆分排序字段与方向
如果需要更灵活的排序组合,可以拆分出sort_field和sort_direction两个参数:
# 先定义排序方向枚举 module Types class SortDirectionEnum < Types::BaseEnum value "ASC", description: "升序" value "DESC", description: "降序" end end # 在CategoryType中修改shoes字段 field :shoes, [Types::ShoeType], null: false do argument :sort_field, String, required: false, default_value: "created_at", validates: { inclusion: { in: ["price", "name", "created_at"] } } argument :sort_direction, Types::SortDirectionEnum, required: false, default_value: "DESC" end def shoes(sort_field:, sort_direction:) shoe_table = Shoe.arel_table sort_clause = shoe_table[sort_field.to_sym].public_send(sort_direction.downcase.to_sym) object.shoes.order(sort_clause) end
关键说明
- 之前报错
Field 'shoes' doesn't accept argument 'order_by'的原因是没有在字段定义中显式声明该参数,GraphQL Schema无法识别。 - 使用Arel构建排序条件可以避免直接拼接字符串带来的SQL注入风险,是更安全的做法。
- 枚举类型能强制限定参数的合法取值,减少非法输入导致的错误。
内容的提问来源于stack exchange,提问作者Davide Fazio
相关产品推荐
相关产品推荐

