【问题标题】:How to pass query params to Rails API controller?如何将查询参数传递给 Rails API 控制器?
【发布时间】:2020-05-14 17:49:03
【问题描述】:

在我的 Ruby on Rails 应用中,自行车租赁公司可以管理他们所有的自行车(预订、付款等)。

上下文 我想为自行车租赁公司 (shops) 提供在他们自己的网站上实施预订表格的选项,这样他们就可以让客户预订bike

  • 然后此预订表格将显示bike_categories,其中bikes 可用于给定的arrivaldeparture 日期。

问题 为了管理这个,我想生成一个 API 控制器操作,显示某个 bike_categoryavailability,显示属于这个 bike_category 的可用 bikes 数量的 count

根据这篇文章

Design RESTful query API with a long list of query parameters

我应该能够在我的 api 中处理查询,但是如何在我的 Rails 控制器中获取查询?

代码

模型

class Shop < ApplicationRecord
  has_many :bike_categories, dependent: :destroy
  has_many :bikes, through: :bike_categories
  has_many :reservations, dependent: :destroy
end

class Reservation < ApplicationRecord
  belongs_to :shop
  belongs_to :bike
end

class Bike < ApplicationRecord
  belongs_to :bike_category
  has_many :reservations, dependent: :destroy
end

class BikeCategory < ApplicationRecord
  belongs_to :shop
  has_many :bikes, dependent: :destroy
end

路线

# api
  namespace :api, defaults: { format: :json } do
    namespace :v1 do
      resources :shops, only: [ :show ]
      resources :reservations, only: [ :show, :create ]
      resources :bike_categories, only: [:index, :show, :availability]
    end
  end

控制器/api/v1/bike_categories_controller.rb


class Api::V1::BikeCategoriesController < Api::V1::BaseController
  acts_as_token_authentication_handler_for User, only: [:show, :index, availability]

  def availability
    # How to get the bike_category, arrival and departure?
  end

end

【问题讨论】:

  • @Int'lManOfCodingMystery 或不使用 POST 请求并发送查询参数...这显然是 POST 不适合的情况,因为您没有创建资源并且操作是幂等的。

标签: ruby-on-rails json api-design


【解决方案1】:

您可以使用 has_scope gem

在您的 Bike 模型中,您可以创建范围 not_reserved(我假设您将到达和离开的列命名为 arrive_atdeparture_at

class Bike < ApplicationRecord
# ...
  scope :not_reserved, -> arrive, departure { left_outer_joins(:reservations).distinct.where("reservations.arrival_at < ? AND reservations.departure_at > ?", departure, arrive) }
  # If you need to return the result for a specific bike category
  scope :by_bike_category, -> bike_category_id { where(bike_category_id: bike_category_id) }
# ...
end

在您的 BikeCategoriesController 中:

class Api::V1::BikeCategoriesController < Api::V1::BaseController
  has_scope :not_reserved, using: [:arrive, :departure], type: :hash
  has_scope :by_bike_category

  def availability
    category_availability = apply_scopes(Bike).group(:bike_category_id).count

    render json: category_availability
  end

end

你的查询字符串会是这样的:

?not_reserved[arrive]=20200110&not_reserved[departure]=20200125&by_bike_category=3

【讨论】:

    【解决方案2】:

    Rails 在 params 哈希中提供查询字符串参数,这实际上是以下内容的混搭:

    • 请求正文(对于具有正文的 POST、PATCH、PUT 等方法)
    • 查询字符串
    • 路径中的命名段(例如params[:id])。

    所以真的没什么:

    class Api::V1::BikeCategoriesController < Api::V1::BaseController
      acts_as_token_authentication_handler_for User, only: [:show, :index, availability]
      def availability
        # How to get the bike_category, arrival and departure?
        bike_category = params[:bike_categories] 
        arrival = params[:arrival]
        departure = params[:departure]
      end
    end
    

    但是您的路线配置不正确。您实际上没有availiblity 的路线。 onlyexcept 选项仅限制 resources 生成的默认 CRUD 路由的输出。因此有效值为:

    • 显示
    • 索引
    • 创建
    • 编辑
    • 更新
    • 删除

    任何其他值都没有任何影响。如果你想添加一个额外的 RESTful 路由,你可以这样做:

    resources :bike_categories, only: [:index, :show] do
      # GET .../bike_categories/:bike_category_id/availability 
      get :availability 
    
      # GET .../bike_categories/:id/availability 
      get :availability, on: :member
    
      # GET .../bike_categories/availability 
      get :availability, on: :collection
    end
    

    【讨论】:

    • 感谢 Max 的详尽回答!
    猜你喜欢
    • 2013-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-09
    • 2018-07-14
    • 1970-01-01
    • 2022-10-31
    相关资源
    最近更新 更多