在Rails 5 API中管理多个GET参数

时间:2016-08-26 23:40:41

标签: ruby-on-rails ruby-on-rails-5 rails-api

我使用Rails 5 API构建了一个用于检索数据的应用。我想使用多个GET参数来提取数据。

示例GET请求格式

/users?company=Samsung&position=Engineer

单个参数的控制器代码: -

def index
client = User.where("company = ?", params[:company])
render json: client
end

多个参数的控制器代码: -

def index
client = User.where("company = ?", params[:company]).where("position = ?", params[:position])
render json: client
end
  

同样,GET请求中可能包含/可能不包含许多参数。

我想要什么

如果用户未指定任何参数,则应向他显示所有用户。 如果只指定了几个参数,则只应搜索那些参数。

发生了什么

如果用户在GET请求中仅指定位置参数,则Rails无法处理它&显示一个空白的json,因为没有为它指定规则。

  

请注意,有许多参数,并且无法为每个参数组合编写规则。

1 个答案:

答案 0 :(得分:2)

您的解决方案的基本问题是它强制每个地方依次执行。这意味着如果company参数为nil,则会得到一个空关系,之后的所有where语句都将返回一个空关系。只有在提供参数时才需要有条件地过滤。

您尝试做的最好是在查询/搜索或过滤器对象中完成(查询接受参数并返回结果集,过滤器获取已生成的集合并将其过滤掉)。我想在app/services/中定义这些内容,尽管有些人将它们放在app/queries中。

您的方法中存在一些不一致,但索引端点应返回对象列表。即使你希望找回一个选项,你也应该期望有多个选项。假设我们修复了你的索引端点并使用了一个过滤器对象。

# app/controllers/users_controller.rb
def index
  users = User.where(1=1)
  users = Users::Filter.call(users, params)
  render json: users
end

你会注意到我使用User.where(1=1),这是因为我用来处理rails 3,如果你使用User.all,它会返回一个数组而不是关系。

# /app/services/users/filter.rb
class Users::Filter
  def self.call(resources, options)
    new(users, options).filter
  end

  private

  attr_reader :resources, :options

  def initialize(resources, options)
    @resources = resources
    @options   = options
  end

  def filter
    if options[:company]
      @resources = resources.where(company: options[:company])
    end

    if options[:position]
      @resources = resources.where(position: options[:position])
    end

    resources
  end
end

我使用call然后调用私有initializefilter方法的原因是这个类没有被错误地使用。它有一个单一的入口点并返回结果集。这也允许我将我的过滤功能分解成易于更改的小块大小。

对于这个例子,我在filter中完成了所有过滤,但你可以将它们分解为方法,甚至可以使用一些聪明的元编程来调用过滤器名称,如果对象响应它。

编辑:

您也可以考虑寻找像ransack [1]这样的宝石解决方案,它允许您将参数直接传递给对象并进行搜索。有许多不同类型的搜索/过滤宝石可以满足您的需求。

[1] https://github.com/activerecord-hackery/ransack