2016-07-16 117 views
1

我正在使用ransack gem在rails应用程序中进行搜索。我需要在User表中搜索email_ids的数组。如何通过ransack gem搜索数组?

参考在洗劫this问题,我遵循的步骤,并已将此添加到初始化文件夹ransack.rb

Ransack.configure do |config| 
    { 
    contained_within_array: :contained_within, 
    contained_within_or_equals_array: :contained_within_or_equals, 
    contains_array: :contains, 
    contains_or_equals_array: :contains_or_equals, 
    overlap_array: :overlap 
    }.each do |rp, ap| 
    config.add_predicate rp, arel_predicate: ap, wants_array: true 
    end 
end 

在轨控制台,如果我这样做:

a = User.search(email_contains_array: ['[email protected]']) 

它产生sql像这样:

"SELECT \"users\".* FROM \"users\" WHERE \"users\".\"deleted_at\" IS NULL AND (\"users\".\"email\" >> '---\n- [email protected]\n')" 

并给出e RROR这样的:

User Load (1.8ms) SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL AND ("users"."email" >> '--- 
- [email protected] 
') 
ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR: operator does not exist: character varying >> unknown 
LINE 1: ...RE "users"."deleted_at" IS NULL AND ("users"."email" >> '--- 
                  ^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts. 
: SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL AND ("users"."email" >> '--- 
- [email protected] 
') 

预期的那样,这个查询:

SELECT "users".* FROM "users" WHERE ("users"."roles" @> '{"3","4"}') 

什么是错的我在干嘛?

回答

0

我遇到了和你一样的问题。我使用Rails 5,我需要寻找的roles阵列,User

看来,你已经在你的Gemfile添加postgres_ext gem,但如果你是在Rails的5应用程序中使用它有一些问题。

所以这是一个选择,为你自己添加在阿雷尔节点上contain查询,而不是使用postgres_ext gem

如果你正在使用Rails的其他版本,我觉得它工作得很好了。

我有一个User模型,以及一个数组属性roles。我想要做的是使用ransack来搜索roles。这与你的情况一样。

ransack无法搜索数组。 但PostgresSQL可以搜索阵列像这样:

User.where("roles @> ?", '{admin}').to_sql)

它产生的SQL查询是这样的:

SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL AND (roles @> '{admin}') 

所以我想要做的就是添加一个类似中包含查询在Arel Nodes

您可以做到this way

# app/config/initializers/arel.rb 

require 'arel/nodes/binary' 
require 'arel/predications' 
require 'arel/visitors/postgresql' 

module Arel 
    class Nodes::ContainsArray < Arel::Nodes::Binary 
    def operator 
     :"@>" 
    end 
    end 

    class Visitors::PostgreSQL 
    private 

    def visit_Arel_Nodes_ContainsArray(o, collector) 
     infix_value o, collector, ' @> ' 
    end 
    end 

    module Predications 
    def contains(other) 
     Nodes::ContainsArray.new self, Nodes.build_quoted(other, self) 
    end 
    end 
end 

因为你可以自定义洗劫谓语, 所以加contains洗劫谓词像this

# app/config/initializers/ransack.rb 

Ransack.configure do |config| 
    config.add_predicate 'contains', 
    arel_predicate: 'contains', 
    formatter: proc { |v| "{#{v}}" }, 
    validator: proc { |v| v.present? }, 
    type: :string 
end 

完成!现在

,你可以搜索数组:

User.ransack(roles_contains: 'admin') 

的SQL查询将是这样的:

SELECT \"users\".* FROM \"users\" WHERE \"users\".\"deleted_at\" IS NULL AND (\"users\".\"roles\" @> '{[\"admin\"]}') 

呀!