簡體   English   中英

在RAILS API控制器索引操作中應用過濾器哈希是否有DRY方法?

[英]Is there a DRY approach to applying a filter hash in a RAILS API controller index action?

根據JSON API規范,我們應該使用過濾器查詢參數來過濾控制器中的記錄。 filter參數實際上並沒有真正指定,但由於它應該能夠包含多個搜索條件,顯而易見的事情是使用哈希。

問題是,似乎我經常在控制器動作中為不同類型的記錄重復自己。

以下是僅包含id列表(獲取多個特定記錄)的過濾器的內容。

def index
  if params[:filter] and params[:filter][:id]
    ids = params[:filter][:id].split(",").map(&:to_i)
    videos = Video.find(ids)
  else
    videos = Video.all
  end
  render json: videos
end

對於嵌套屬性檢查,我想我可以使用fetchandand但它仍然看起來不夠干燥,我仍然在不同的控制器上做同樣的事情。

有沒有辦法讓我看起來更好看,而不是重復那么多?

而不是使用關注點在多個位置包含相同的代碼,這似乎是服務對象的一個​​很好的用途。

class CollectionFilter
    def initialize(filters={})
        @filters = filters
    end

    def results
        model_class.find(ids)
    end

    def ids
        return [] unless @filters[:id]
        @filters[:id].split(",").map(&:to_i)
    end

    def model_class
        raise NotImplementedError
    end
end

您可以像上面那樣編寫一個通用的CollectionFilter ,然后再創建子類來為特定的用例添加功能。

class VideoFilter < CollectionFilter
    def results
        super.where(name: name)
    end

    def name
        @filters[:name]
    end

    def model_class
        Video
    end
end

您可以在控制器中使用它,如下所示;

def index
    videos = VideoFilter.new(params[:filter]).results
    render json: videos
end

你可以使用Rails Concerns來干涸......

    ##================add common in app/models/concerns/common.rb
    module Common
      extend ActiveSupport::Concern  

      #  included do
      ##add common scopes /validations
      # end

      ##NOTE:add any instance method outside this module
      module ClassMethods
        def Find_using_filters (params)
          Rails.logger.info "calling class method in concern=======#{params}=="
          ##Do whatever you want with params now
          #you can even use switch case in case there are multiple models

        end
    end
  end

##======================include the concern in model
include Common

##=======================in your controller,call it directly    
 Image.Find_using_filters params

以下是我對此的看法,有點改編自Justin Weiss的方法

# app/models/concerns/filterable.rb
module Filterable
  extend ActiveSupport::Concern

  class_methods do
    def filter(params)
      return self.all unless params.key? :filter

      params[:filter].inject(self) do |query, (attribute, value)|
        query.where(attribute.to_sym => value) if value.present?
      end
    end
  end
end

# app/models/user.rb
class User < ActiveRecord::Base
  include Filterable
end

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  # GET /users
  # GET /users?filter[attribute]=value
  def index
    @users = User.filter(filter_params)
  end

  private
    # Define which attributes can this model be filtered by
    def filter_params
      params.permit(filter: :username)
    end
end

然后,您將通過發出GET /users?filter[username]=joe過濾結果。 這適用於沒有過濾器(返回User.all )或沒有值的過濾器(它們只是被跳過)。

filter符合JSON-API。 通過模型關注,您可以將代碼保留為DRY,並且只將其包含在您要過濾的任何模型中。 我也使用強大的參數來對“可怕的互聯網”實施某種保護。

當然,您可以自定義此問題並使其支持數組作為過濾器的值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM