5

根据 JSON API 规范,我们应该使用过滤器查询参数来过滤控制器中的记录。过滤器参数实际上是什么并没有真正指定,但是由于它应该能够包含多个搜索条件,所以显而易见的事情是使用哈希。

问题是,对于不同类型的记录,我似乎经常在控制器操作中重复自己。

以下是仅包含 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

对于嵌套属性检查,我想我可以使用fetchorandand但它仍然看起来不够干,而且我仍然在不同的控制器上做同样的事情。

有没有办法让这看起来更好,而不是重复自己那么多?

4

3 回答 3

4

与其使用关注点在多个位置包含相同的代码,这似乎是服务对象的一个​​很好的用途。

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
于 2015-07-29T09:32:56.137 回答
2

这是我对此的看法,在某种程度上改编自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。通过关注模型,您可以保持代码干燥,并且只将其包含在您想要过滤的任何模型中。我还使用了强大的参数来对“可怕的互联网”实施某种保护。

当然,您可以自定义此关注点并使其支持数组作为过滤器的值。

于 2015-10-12T20:05:49.643 回答
1

你可以使用Rails 的关注来干涸......

    ##================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
于 2015-07-29T09:15:41.210 回答