module Ransack::Helpers
Public Instance Methods
attribute_collection_for_base(base)
click to toggle source
# File lib/ransack_ui/ransack_overrides/helpers/form_builder.rb, line 142 def attribute_collection_for_base(base) klass = object.context.traverse(base) ajax_options = Ransack.options[:ajax_options] || {} # Detect any inclusion validators to build list of options for a column column_select_options = klass.validators.each_with_object({}) do |v, hash| next unless v.is_a? ActiveModel::Validations::InclusionValidator v.attributes.each do |a| # Try to translate options from activerecord.attribute_options.<model>.<attribute> inclusions = v.send(:delimiter) inclusions = inclusions.call if inclusions.respond_to?(:call) # handle lambda hash[a.to_s] = inclusions.each_with_object({}) do |o, options| options[o.to_s] = I18n.translate("activerecord.attribute_options.#{klass.to_s.downcase}.#{a}.#{o}", default: o.to_s.titleize) end end end column_select_options.merge!(klass.ransack_column_select_options) if klass.respond_to?(:ransack_column_select_options) searchable_attributes_for_base(base).map do |attribute_data| column = attribute_data[:column] html_options = {} # Add column type as data attribute html_options[:'data-type'] = attribute_data[:type] # Set 'base' attribute if attribute is on base model html_options[:'data-root-model'] = true if base.blank? # Set column options if detected from inclusion validator if column_select_options[column] # Format options as an array of hashes with id and text columns, for Select2 html_options[:'data-select-options'] = column_select_options[column].map do |id, text| { id: id, text: text } end.to_json end foreign_klass = attribute_data[:foreign_klass] if foreign_klass # If field is a foreign key, set up 'data-ajax-*' attributes for auto-complete controller = ActiveSupport::Inflector.tableize(foreign_klass.to_s) html_options[:'data-ajax-entity'] = I18n.translate(controller, default: controller) if ajax_options[:url] html_options[:'data-ajax-url'] = ajax_options[:url].sub(':controller', controller) else html_options[:'data-ajax-url'] = "/#{controller}.json" end html_options[:'data-ajax-type'] = ajax_options[:type] || 'GET' html_options[:'data-ajax-key'] = ajax_options[:key] || 'query' end [ attribute_data[:label], attribute_data[:attribute], html_options ] end rescue UntraversableAssociationError nil end
attribute_collection_for_bases(bases)
click to toggle source
# File lib/ransack_ui/ransack_overrides/helpers/form_builder.rb, line 131 def attribute_collection_for_bases(bases) bases.map do |base| next unless (collection = attribute_collection_for_base(base)) [ Translate.association(base, context: object.context), collection ] end.compact end
attribute_select(options = {}, html_options = {})
click to toggle source
# File lib/ransack_ui/ransack_overrides/helpers/form_builder.rb, line 9 def attribute_select(options = {}, html_options = {}) raise ArgumentError, 'attribute_select must be called inside a search FormBuilder!' unless object.respond_to?(:context) options[:include_blank] = true unless options.key?(:include_blank) # Set default associations set on model with 'has_ransackable_associations' options[:associations] = object.context.klass.ransackable_associations if options[:associations].nil? bases = [''] + association_array(options[:associations]) if bases.size > 1 @template.select( @object_name, :name, @template.grouped_options_for_select(attribute_collection_for_bases(bases), object.name), objectify_options(options), @default_options.merge(html_options) ) else @template.select( @object_name, :name, attribute_collection_for_base(bases.first), objectify_options(options), @default_options.merge(html_options) ) end end
foreign_klass_for_attribute(attribute)
click to toggle source
# File lib/ransack_ui/ransack_overrides/helpers/form_builder.rb, line 244 def foreign_klass_for_attribute(attribute) associations = object.context.klass.ransackable_associations bases = [''] + association_array(associations) bases.each do |base| searchable_attributes_for_base(base).each do |attribute_data| return attribute_data[:foreign_klass] if attribute == attribute_data[:attribute] end end end
labels_for_value_fields()
click to toggle source
# File lib/ransack_ui/ransack_overrides/helpers/form_builder.rb, line 64 def labels_for_value_fields labels = {} object.groupings.each do |grouping| grouping.conditions.each do |condition| condition.values.each do |value| # If value is present, and the attribute is an association, # load the selected record and include the record name as a data attribute next unless value.value.present? condition_attributes = condition.attributes next unless condition_attributes.any? attribute = condition_attributes.first.name klass_name = foreign_klass_for_attribute(attribute) next unless klass_name klass = klass_name.constantize value_object = klass.find_by_id(value.value) next unless value_object labels[attribute] ||= {} if value_object.respond_to? :full_name labels[attribute][value.value] = value_object.full_name elsif value_object.respond_to? :name labels[attribute][value.value] = value_object.name end end end end labels end
predicate_keys(options)
click to toggle source
# File lib/ransack_ui/ransack_overrides/helpers/form_builder.rb, line 101 def predicate_keys(options) keys = options[:compounds] ? Predicate.names : Predicate.names.reject { |k| k.match(/_(any|all)$/) } if (only = options[:only]) if only.respond_to? :call keys = keys.select { |k| only.call(k) } else only = Array.wrap(only).map(&:to_s) # Create compounds hash, e.g. {"eq" => ["eq", "eq_any", "eq_all"], "blank" => ["blank"]} key_groups = keys.inject(Hash.new([])) { |h, k| h[k.sub(/_(any|all)$/, '')] += [k]; h } # Order compounds hash by 'only' keys keys = only.map { |k| key_groups[k] }.flatten.compact end end keys end
predicate_select(options = {}, html_options = {})
click to toggle source
# File lib/ransack_ui/ransack_overrides/helpers/form_builder.rb, line 117 def predicate_select(options = {}, html_options = {}) options = Ransack.options[:default_predicates] || {} if options.blank? options[:compounds] = true if options[:compounds].nil? keys = predicate_keys(options) # If condition is newly built with build_condition(), # then replace the default predicate with the first in the ordered list @object.predicate_name = keys.first if @object.default? @template.collection_select( @object_name, :p, keys.map { |k| [k, Translate.predicate(k)] }, :first, :last, objectify_options(options), @default_options.merge(html_options) ) end
searchable_attributes_for_base(base)
click to toggle source
# File lib/ransack_ui/ransack_overrides/helpers/form_builder.rb, line 207 def searchable_attributes_for_base(base) cache_prefix = object.context.klass.table_name cache_key = base.blank? ? cache_prefix : [cache_prefix, base].join('_') self.class.cached_searchable_attributes_for_base[cache_key] ||= object.context.searchable_attributes(base).map do |column, type| klass = object.context.traverse(base) foreign_keys = klass.reflect_on_all_associations.select(&:belongs_to?) .each_with_object({}) { |r, h| h[r.foreign_key.to_sym] = r.class_name } # Don't show 'id' column for base model next nil if base.blank? && column == 'id' attribute = attr_from_base_and_column(base, column) attribute_label = Translate.attribute(attribute, context: object.context) # Set model name as label for 'id' column on that model's table. if column == 'id' foreign_klass = object.context.traverse(base).model_name # Check that model can autocomplete. If not, skip this id column. next nil unless ActiveSupport::Inflector.constantize(foreign_klass.to_s)._ransack_can_autocomplete attribute_label = I18n.translate(foreign_klass, default: foreign_klass) else foreign_klass = foreign_keys[column.to_sym] end attribute_data = { label: attribute_label, type: type, column: column, attribute: attribute } attribute_data[:foreign_klass] = foreign_klass if foreign_klass attribute_data end.compact end
sort_select(options = {}, html_options = {})
click to toggle source
# File lib/ransack_ui/ransack_overrides/helpers/form_builder.rb, line 32 def sort_select(options = {}, html_options = {}) raise ArgumentError, 'sort_select must be called inside a search FormBuilder!' unless object.respond_to?(:context) options[:include_blank] = true unless options.key?(:include_blank) bases = [''] + association_array(options[:associations]) if bases.size > 1 @template.select( @object_name, :name, @template.grouped_options_for_select(attribute_collection_for_bases(bases), object.name), objectify_options(options), @default_options.merge(class: 'ransack_sort').merge(html_options) ) + @template.collection_select( @object_name, :dir, [['asc', object.translate('asc')], ['desc', object.translate('desc')]], :first, :last, objectify_options(options.except(:include_blank)), @default_options.merge(class: 'ransack_sort_order').merge(html_options) ) else # searchable_attributes now returns [c, type] collection = object.context.searchable_attributes(bases.first).map do |c, _type| [ attr_from_base_and_column(bases.first, c), Translate.attribute(attr_from_base_and_column(bases.first, c), context: object.context) ] end @template.collection_select( @object_name, :name, collection, :first, :last, objectify_options(options), @default_options.merge(class: 'ransack_sort').merge(html_options) ) + @template.collection_select( @object_name, :dir, [['asc', object.translate('asc')], ['desc', object.translate('desc')]], :first, :last, objectify_options(options.except(:include_blank)), @default_options.merge(class: 'ransack_sort_order').merge(html_options) ) end end