【问题标题】:Rails how to use where method for search or return all?Rails如何使用where方法进行搜索或全部返回?
【发布时间】:2019-01-21 11:13:31
【问题描述】:

我正在尝试在我的 Rails API 中搜索 Address 的多个属性。

我想按州、城市和/或街道进行搜索。但是用户不需要发送所有属性,他可以根据需要只按城市搜索。

所以我需要这样的东西:如果条件存在按条件搜索或返回此条件的所有结果。

示例:

搜索请求:street = 'some street', city = '', state = ''

如果某些条件为零,我如何使用 rails where 方法返回全部?

我正在尝试这样的事情,但我知道||:all 不起作用,它只是为了说明我的想法。:

def get_address
  address = Adress.where(
    state: params[:state] || :all,
    city: params[:city] || :all,
    street: params[:street] || :all)
end

有可能做这样的事情吗?或者也许有更好的方法?

【问题讨论】:

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


    【解决方案1】:

    这是一个使用一些简单哈希操作的更优雅的解决方案:

    def filter_addesses(scope = Adress.all)
      # slice takes only the keys we want
      # compact removes nil values
      filters = params.permit(:state, :city, :street).to_h.compact
      scope = scope.where(filters) if filters.any?
      scope
    end
    

    【讨论】:

    • 谢谢你 max,我刚刚编辑了你的答案以关注 this new rails 5 changes
    • 你是对的,但你的解决方案有点过头了。只需更改 slice 以允许解决问题。
    • 我认为params.to_h 也是需要的,正如上面链接的第一个答案所说:Rails 5 ActionController::Parameters 现在返回一个对象而不是哈希
    • 你又是对的。 ActionController::Parameters.new(state: 'VT', city: 'Montpelier').permit(:state, :city, :street).to_h.compact 成功了。
    【解决方案2】:

    一旦您将一列传递给where,就没有一个选项意味着“再三考虑不要按此过滤”。相反,您可以逐步构建关系:

    def get_address
      addresses = Address.all
      addresses = addresses.where(state: params[:state]) if params[:state]
      addresses = addresses.where(city: params[:city]) if params[:city]
      addresses = addresses.where(street: params[:street]) if params[:street]
      addresses
    end
    

    【讨论】:

    • 这种模式不会让你的控制器保持瘦身。随着时间的推移,可能会添加其他参数,这将使您的控制器更加混乱。请考虑使用搜索对象模式并将此逻辑封装到 Ruby PORO 中。
    【解决方案3】:

    我强烈推荐使用Searchlight gem。它准确地解决了您所描述的问题。不要把你的控制器弄得乱七八糟,把你的搜索 params 传递给一个 Searchlight 类。这将使您的代码干燥,并使您的控制器也很瘦。您不仅会解决您的问题,还会拥有更多可维护的代码。双赢!

    因此,在您的情况下,您将创建一个 AddressSearch 类:

    class AddressSearch < Searchlight::Search
    
      # This is the starting point for any chaining we do, and it's what
      # will be returned if no search options are passed.
      # In this case, it's an ActiveRecord model.
      def base_query
        Address.all # or `.scoped` for ActiveRecord 3
      end
    
      # A search method.
      def search_state
        query.where(state: options[:state])
      end
    
      # Another search method.
      def search_city
        query.where(city: options[:city])
      end
      # Another search method.
      def search_street
        query.where(street: options[:street])
      end
    end
    

    然后在您的控制器中,您只需将搜索参数传递到上面的类中进行搜索:

    AddressSearch.new(params).results
    

    这个 gem 的一个好处是任何无关的参数都会被 Searchlight 自动清除。仅使用州、市和街道参数。

    【讨论】:

    • 谢谢你!我认为对我有很大帮助
    猜你喜欢
    • 2010-11-11
    • 2014-08-27
    • 1970-01-01
    • 1970-01-01
    • 2020-12-15
    • 2019-11-10
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    相关资源
    最近更新 更多