Module: HasArrayScopes::Taggable::ClassMethod

Defined in:
lib/has_array_scopes/taggable.rb

Overview

Class-level helpers extended onto the including class — provides
the array_scope macro and the dispatch into Ransack so the
taggable column can be queried via the standard q[] form params.

Instance Method Summary collapse

Instance Method Details

#has_array_scopes(tag_name) ⇒ void

This method returns an undefined value.

Returns defines array-tag scopes on the model.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/has_array_scopes/taggable.rb', line 25

def has_array_scopes(tag_name, *)
  quoted_tag = connection.quote_column_name(tag_name)
  quoted_table = connection.quote_table_name(table_name)
  tag_array_type_fetcher = lambda {
    col_type = columns_hash[tag_name.to_s]&.type
    TYPE_MATCHER.fetch(col_type) do
      raise ArgumentError, "Unsupported column type #{col_type.inspect} for has_array_scopes :#{tag_name}"
    end
  }
  parser = HasArrayScopes::Parser.new

  scope :"with_any_#{tag_name}", ->(tags) { where("#{quoted_table}.#{quoted_tag} && ARRAY[?]::#{tag_array_type_fetcher.call}[]", parser.parse(tags)) }
  scope :"with_all_#{tag_name}", ->(tags) { where("#{quoted_table}.#{quoted_tag} @> ARRAY[?]::#{tag_array_type_fetcher.call}[]", parser.parse(tags)) }
  scope :"without_any_#{tag_name}", ->(tags) { where.not("#{quoted_table}.#{quoted_tag} && ARRAY[?]::#{tag_array_type_fetcher.call}[]", parser.parse(tags)) }
  scope :"without_all_#{tag_name}", ->(tags) { where.not("#{quoted_table}.#{quoted_tag} @> ARRAY[?]::#{tag_array_type_fetcher.call}[]", parser.parse(tags)) }

  define_singleton_method :"all_#{tag_name}" do |_options = {}, &block|
    subquery_scope = unscoped.select("unnest(#{quoted_table}.#{quoted_tag}) as tag").order(1).distinct
    subquery_scope = subquery_scope.instance_eval(&block) if block
    unscope(:where).from(subquery_scope).pluck("tag")
  end

  define_singleton_method :"#{tag_name}_cloud" do |_options = {}, &block|
    subquery_scope = unscoped.select("unnest(#{quoted_table}.#{quoted_tag}) as tag")
    subquery_scope = subquery_scope.instance_eval(&block) if block
    unscope(:where).from(subquery_scope).group("tag").order(:tag).pluck(Arel.sql("tag, count(*) as count"))
  end
end