【问题标题】:Rails Ransack search PG hstoreRails Ransack 搜索 PG hstore
【发布时间】:2014-10-14 07:24:02
【问题描述】:

我在 Rails4 应用程序中使用 Ransack。我最近在表中添加了一个 PG hstore 字段。在这个应用程序中,用户可以定义 hstore 字段内容(键和值)。

如果我知道密钥名称,我找到了一种使用 Ransack 搜索 hstore 字段的方法。这是一个示例 - 密钥是color

ransacker :color do |parent|
  Arel::Nodes::InfixOperation.new('->', parent.table[:data], 'color')
end

然后在视图中,我使用:

    <td><%= f.label :color_cont, "Color:" %></td>
    <td><%= f.text_field :color_cont %></td>

但是,我不知道用户会为key 使用什么。

有没有人想出办法在不知道密钥的情况下 Ransack 搜索 hstore 字段?

感谢您的帮助!

【问题讨论】:

    标签: ruby-on-rails ransack


    【解决方案1】:

    您可能可以直接使用 Arel::Nodes 执行此操作,但您也可以使用 Ransack 更高版本中添加的 ransackable_scopes 方法。

    首先创建一个方法来返回您的 hstore_col_name。

    然后在 hstore 列上创建一些使用 postgres 运算符的作用域。第一个范围可用于查找具有 key_value_pair 的行。第二个作用域可用于查找具有给定键和任何值的行,这也可能会有所帮助。

    scope :with_key_value_pair, ->(key,value){where("#{table_name}.#{hstore_col_name} @> '#{key}=>#{value}'")}
    scope :with_key, ->(key){where("#{table_name}.#{hstore_col_name} ? :key", :key=>key)}
    

    然后创建一个类方法,该方法将动态返回该 hstore 列中正在使用的所有当前唯一键的数组:

    def self.hstore_keys_to_a
      self.connection.execute("SELECT DISTINCT UNNEST(AKEYS(#{hstore_col_name})) from #{table_name}").map(&:values).flatten.uniq
    end
    

    由于我没有找到在一个范围内使用带有两个参数的 ransack 的任何示例,因此我创建了另一个类方法来动态添加范围以供 ransack 调用,以匹配 hstore 列中当前使用的每个键。也许有一种更直接的方法来传递两个参数,而不是像我在这里所做的那样将一个参数放入作用域名称中:

    def self.add_hstore_key_scopes do
      hstore_keys_to_a.each do |key|
        define_singleton_method "with_#{key}" do |val|
          with_key_value_pair(key,val)
        end
      end
    end
    
    def self.ransackable_scopes(auth_obj=nil)
      hstore_keys_to_a.map{|key| "with_#{key}"} << "with_key"
    end
    

    我将静态 'with_key' 范围附加到 ransackable_scopes 以允许选择搜索具有给定键和任何值的行。

    然后在搜索表单的rails控制器方法中,在渲染前调用Model.add_hstore_key_scopes。这将确保任何最近添加的键也都为它们添加了 with_#{key} 范围。

    现在在视图中,您可以为当前使用的每个键渲染一个部分:

    <% Model.hstore_keys_to_a.each do |key| %>
      <%= f.label "with_#{key}" %>
      <%= f.text_field "with_#{key}" %>
    <% end %>
    

    如果您愿意,还可以使用另一个字段来搜索具有任意值的给定键的行:

    <%= f.label "with_key" %>
    <%= f.text_field "with_key" %>
    

    【讨论】:

      【解决方案2】:

      我最终在车辆模型中这样做了:

      if ActsAsTenant.current_tenant.data.present?
        ActsAsTenant.current_tenant.data.each do |key, value|
          ransacker key do |parent|
            Arel::Nodes::InfixOperation.new('->', parent.table[:data], key)
          end
        end
      end
      

      而这在视图中:

            <% if current_tenant.data.present? %>
                <% current_tenant.data.each do |key, value| %>
                    <td><%= f.label key + '_cont', key.capitalize + ":" %></td>
                    <td><%= f.text_field key + '_cont' %></td>
                <% end %>
            <% end %>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-06
        • 1970-01-01
        • 2012-09-18
        • 1970-01-01
        • 2022-08-17
        • 2013-03-02
        • 2015-02-15
        相关资源
        最近更新 更多