Rails 5.1 API-具有过滤器,分页和作用域的索引方法-如何简化

时间:2019-03-24 20:23:59

标签: ruby-on-rails ruby controller

我在Rails API控制器中有一个索引方法,这很可怕,如下所示。

我确信还有更多的Ruby或Rails方式可以编写此代码。

该操作支持分页和过滤(通过filter =查询参数),并且还可以提供客户ID,以将返回的内容限制为仅与所提供的客户相关的投标。

我想知道是否应该将客户功能分离到单独的端点? (例如客户/:id /提案)。当然,该端点还需要支持分页和过滤器,因此我认为我可能不会以DRY代码结尾。有没有一种方法(像关注问题一样)可以使该索引代码更简单(即没有所有if...then...else)?

  def index
    if params[:page].present?
      page = params[:page]
      if params[:filter].present?
        if params[:customer_id].present?
          @proposals = current_user.retailer.proposals.customer(params[:customer_id]).search(params.slice(:filter)).page(page)
        else
          @proposals = current_user.retailer.proposals.search(params.slice(:filter)).page(page)
        end
      else
        if params[:customer_id].present?
          @proposals = current_user.retailer.proposals.customer(params[:customer_id]).page(page)
        else
          @proposals = current_user.retailer.proposals.page(page)
        end
      end
      render json: @proposals, root: 'proposals', meta: pagination_dict(@proposals)
    else
      render status: :bad_request, json: { message: "Please supply page parameter" }
    end
  end

以下是Proposal模型范围:

  default_scope { order("updated_at DESC") }
  scope :filter, -> (term) { where("lower(first_name) || ' ' || lower(last_name) || ' ' || lower(email) LIKE ? OR qd_number::text LIKE ?", "%#{term.downcase}%", "%#{term}%") }  
  scope :customer, -> (customer_id) { where customer_id: customer_id }

1 个答案:

答案 0 :(得分:1)

我将从以下内容开始:

def index
  if params[:page].present?
    @proposals = current_user.retailer.proposals.page(params[:page])

    @proposals = @proposals.customer(params[:customer_id]) if params[:customer_id].present?
    @proposals = @proposals.search(params.slice(:filter))  if params[:filter].present?

    render json: @proposals, root: 'proposals', meta: pagination_dict(@proposals)
  else
    render status: :bad_request, json: { message: "Please supply page parameter" }
  end
end

此外,您可能想在before_action中处理错误:

before_action :check_required_parameters, only: :index

def index
  @proposals = current_user.retailer.proposals.page(params[:page])

  @proposals = @proposals.customer(params[:customer_id]) if params[:customer_id].present?
  @proposals = @proposals.search(params.slice(:filter))  if params[:filter].present?

  render json: @proposals, root: 'proposals', meta: pagination_dict(@proposals)
end

private

def check_required_parameters
  return if params[:page].present?

  render status: :bad_request, json: { message: "Please supply page parameter" }
end

或者您可能希望更改范围以处理空白值:

# in the model
scope :filter, -> (term) { where("lower(first_name) || ' ' || lower(last_name) || ' ' || lower(email) LIKE ? OR qd_number::text LIKE ?", "%#{term.downcase}%", "%#{term}%") if term.present? }  
scope :customer, -> (customer_id) { where(customer_id: customer_id) if customer_id.present? }

# in the controller
def index
  if params[:page].present?
    @proposals = current_user.retailer.proposals
      .customer(params[:customer_id])
      .search(params.slice(:filter))
      .page(params[:page])

    render json: @proposals, root: 'proposals', meta: pagination_dict(@proposals)
  else
    render status: :bad_request, json: { message: "Please supply page parameter" }
  end
end