app/models/effective/effective_datatable/resource.rb in effective_datatables-3.6.3 vs app/models/effective/effective_datatable/resource.rb in effective_datatables-3.7.0
- old
+ new
@@ -6,13 +6,17 @@
def admin_namespace?
controller_namespace == 'admin'
end
def controller_namespace
- @attributes[:_n]
+ @attributes[:namespace]
end
+ def association_macros
+ [:belongs_to, :belongs_to_polymorphic, :has_many, :has_and_belongs_to_many, :has_one]
+ end
+
private
def load_effective_resource!
@effective_resource = if active_record_collection?
Effective::Resource.new(collection_class, namespace: controller_namespace)
@@ -21,103 +25,133 @@
# This looks at all the columns and figures out the as:
def load_resource!
load_effective_resource!
- if active_record_collection?
- columns.each do |name, opts|
+ load_active_record_collection!
+ load_active_record_array_collection!
+ load_array_collection!
- # col 'comments.title'
- if name.kind_of?(String) && name.include?('.')
- raise "invalid datatables column '#{name}'. the joined syntax only supports one dot." if name.scan(/\./).count > 1
+ load_resource_columns!
+ load_resource_belongs_tos!
+ load_resource_search!
+ end
- (associated, field) = name.split('.').first(2)
+ def load_effective_resource!
+ @effective_resource = if active_record_collection?
+ Effective::Resource.new(collection_class, namespace: controller_namespace)
+ end
+ end
- unless resource.macros.include?(resource.sql_type(associated))
- raise "invalid datatables column '#{name}'. unable to find '#{name.split('.').first}' association on '#{resource}'."
- end
+ def load_active_record_collection!
+ return unless active_record_collection?
- joins_values = (collection.joins_values + collection.left_outer_joins_values)
+ columns.each do |name, opts|
+ # col 'comments.title'
+ if name.kind_of?(String) && name.include?('.')
+ raise "invalid datatables column '#{name}'. the joined syntax only supports one dot." if name.scan(/\./).count > 1
- unless joins_values.include?(associated.to_sym)
- raise "your datatables collection must .joins(:#{associated}) or .left_outer_joins(:#{associated}) to work with the joined syntax"
- end
+ (associated, field) = name.split('.').first(2)
- opts[:resource] = Effective::Resource.new(resource.associated(associated), namespace: controller_namespace)
+ unless association_macros.include?(effective_resource.sql_type(associated))
+ raise "invalid datatables column '#{name}'. unable to find '#{name.split('.').first}' association on '#{effective_resource}'."
+ end
- if opts[:resource].column(field)
- opts[:as] ||= opts[:resource].sql_type(field)
- opts[:as] = :integer if opts[:resource].sql_type(field) == :belongs_to && field.end_with?('_id')
- opts[:sql_column] = opts[:resource].sql_column(field) if opts[:sql_column].nil?
+ joins_values = (collection.joins_values + collection.left_outer_joins_values)
- opts[:resource].sort_column = field
- opts[:resource].search_columns = field
- end
+ unless joins_values.include?(associated.to_sym)
+ raise "your datatables collection must .joins(:#{associated}) or .left_outer_joins(:#{associated}) to work with the joined syntax"
+ end
- opts[:resource_field] = field
+ opts[:resource] = Effective::Resource.new(effective_resource.associated(associated), namespace: controller_namespace)
- next
+ if opts[:resource].column(field)
+ opts[:as] ||= opts[:resource].sql_type(field)
+ opts[:as] = :integer if opts[:resource].sql_type(field) == :belongs_to && field.end_with?('_id')
+ opts[:sql_column] = opts[:resource].sql_column(field) if opts[:sql_column].nil?
+
+ opts[:resource].sort_column = field
+ opts[:resource].search_columns = field
end
- # Regular fields
- opts[:as] ||= resource.sql_type(name)
- opts[:sql_column] = resource.sql_column(name) if opts[:sql_column].nil?
+ opts[:resource_field] = field
- case opts[:as]
- when *resource.macros
- opts[:resource] ||= Effective::Resource.new(resource.associated(name), namespace: controller_namespace)
+ next
+ end
+
+ # Regular fields
+ opts[:as] ||= effective_resource.sql_type(name)
+ opts[:sql_column] = effective_resource.sql_column(name) if opts[:sql_column].nil?
+
+ case opts[:as]
+ when *association_macros
+ opts[:resource] ||= Effective::Resource.new(effective_resource.associated(name), namespace: controller_namespace)
+ opts[:sql_column] = name if opts[:sql_column].nil?
+ when Class
+ if opts[:as].ancestors.include?(ActiveRecord::Base)
+ opts[:resource] = Effective::Resource.new(opts[:as], namespace: controller_namespace)
+ opts[:as] = :resource
opts[:sql_column] = name if opts[:sql_column].nil?
- when Class
- if opts[:as].ancestors.include?(ActiveRecord::Base)
- opts[:resource] = Effective::Resource.new(opts[:as], namespace: controller_namespace)
- opts[:as] = :resource
- opts[:sql_column] = name if opts[:sql_column].nil?
- end
- when :effective_addresses
- opts[:resource] = Effective::Resource.new(resource.associated(name), namespace: controller_namespace)
- opts[:sql_column] = :effective_addresses
- when :effective_roles
- opts[:sql_column] = :effective_roles
- when :string # This is the fallback
- # Anything that doesn't belong to the model or the sql table, we assume is a SELECT SUM|AVG|RANK() as fancy
- opts[:sql_as_column] = true if (resource.table && resource.column(name).blank?)
end
+ when :effective_addresses
+ opts[:resource] = Effective::Resource.new(effective_resource.associated(name), namespace: controller_namespace)
+ opts[:sql_column] = :effective_addresses
+ when :effective_roles
+ opts[:sql_column] = :effective_roles
+ when :string # This is the fallback
+ # Anything that doesn't belong to the model or the sql table, we assume is a SELECT SUM|AVG|RANK() as fancy
+ opts[:sql_as_column] = true if (effective_resource.table && effective_resource.column(name).blank?)
+ end
- if opts[:sql_column].present? && AGGREGATE_SQL_FUNCTIONS.any? { |str| opts[:sql_column].to_s.start_with?(str) }
- opts[:sql_as_column] = true
- end
+ if opts[:sql_column].present? && AGGREGATE_SQL_FUNCTIONS.any? { |str| opts[:sql_column].to_s.start_with?(str) }
+ opts[:sql_as_column] = true
end
end
+ end
- if array_collection?
- row = collection.first
+ def load_active_record_array_collection!
+ return unless active_record_array_collection?
+ end
- columns.each do |name, opts|
- if opts[:as].kind_of?(Class) && opts[:as].ancestors.include?(ActiveRecord::Base)
- opts[:resource] = Effective::Resource.new(opts[:as], namespace: controller_namespace)
+ def load_array_collection!
+ return unless array_collection?
+
+ row = collection.first
+
+ columns.each do |name, opts|
+ if opts[:as].kind_of?(Class) && opts[:as].ancestors.include?(ActiveRecord::Base)
+ opts[:resource] = Effective::Resource.new(opts[:as], namespace: controller_namespace)
+ opts[:as] = :resource
+ elsif opts[:as] == nil && row.present?
+ if (value = Array(row[opts[:index]]).first).kind_of?(ActiveRecord::Base)
+ opts[:resource] = Effective::Resource.new(value, namespace: controller_namespace)
opts[:as] = :resource
- elsif opts[:as] == nil
- if (value = Array(row[opts[:index]]).first).kind_of?(ActiveRecord::Base)
- opts[:resource] = Effective::Resource.new(value, namespace: controller_namespace)
- opts[:as] = :resource
- end
end
end
end
+ end
+ def load_resource_columns!
columns.each do |name, opts|
opts[:as] ||= :string
opts[:as] = :email if (opts[:as] == :string && name.to_s.end_with?('email'))
+ if opts[:action]
+ opts[:resource] ||= effective_resource
+ end
+
if opts[:resource] && !opts[:resource_field] && opts[:as] != :effective_addresses
opts[:partial] ||= '/effective/datatables/resource_column'
end
- opts[:col_class] = "col-#{opts[:as]} col-#{name.to_s.parameterize} #{opts[:col_class]}".strip
+ opts[:col_class] = [
+ "col-#{opts[:as]}",
+ "col-#{name.to_s.parameterize}",
+ ('colvis-default' if opts[:visible]),
+ opts[:col_class].presence
+ ].compact.join(' ')
end
-
- load_resource_search!
end
def load_resource_search!
columns.each do |name, opts|
@@ -125,54 +159,75 @@
when false
opts[:search] = { as: :null }; next
when Symbol
opts[:search] = { as: opts[:search] }
when Array, ActiveRecord::Relation
- opts[:search] = { collection: opts[:search] }
+ opts[:search] = { as: :select, collection: opts[:search] }
when Hash
# Nothing
else
raise "column #{name} unexpected search value"
end
search = opts[:search]
+ # Parameterize collection
if search[:collection].kind_of?(ActiveRecord::Relation)
search[:collection] = search[:collection].map { |obj| [obj.to_s, obj.to_param] }
elsif search[:collection].kind_of?(Array) && search[:collection].first.kind_of?(ActiveRecord::Base)
search[:collection] = search[:collection].map { |obj| [obj.to_s, obj.to_param] }
- elsif search[:collection].kind_of?(Array)
- search[:collection].each { |obj| obj[1] = 'nil' if obj[1] == nil }
- elsif search[:collection].kind_of?(Hash)
- search[:collection].each { |k, v| search[:collection][k] = 'nil' if v == nil }
end
+ search[:as] ||= :select if search.key?(:collection)
+ search[:fuzzy] ||= true unless search.key?(:fuzzy)
search[:value] ||= search.delete(:selected) if search.key?(:selected)
- search[:as] ||= :select if (search.key?(:collection) && opts[:as] != :belongs_to_polymorphic)
+ # Merge with defaults
+ search_resource = [opts[:resource], effective_resource, fallback_effective_resource].compact
+ search_resource = search_resource.find { |res| res.klass.present? } || search_resource.first
- search[:fuzzy] = true unless search.key?(:fuzzy)
-
if array_collection? && opts[:resource].present?
- search.reverse_merge!(resource.search_form_field(name, collection.first[opts[:index]]))
+ search.reverse_merge!(search_resource.search_form_field(name, collection.first[opts[:index]]))
elsif search[:as] != :string
- search.reverse_merge!(resource.search_form_field(name, opts[:as]))
+ search.reverse_merge!(search_resource.search_form_field(name, opts[:as]))
end
+
+ # Assign default include_null
+ if search[:as] == :select && !search.key?(:include_null)
+ search[:include_null] = true
+ end
end
end
- def apply_belongs_to_attributes!
+ def load_resource_belongs_tos!
return unless active_record_collection?
changed = attributes.select do |attribute, value|
attribute = attribute.to_s
next unless attribute.ends_with?('_id')
associated = attribute.gsub(/_id\z/, '').to_sym # Replace last _id
- next unless columns[associated] && columns[associated][:as] == :belongs_to
- @_collection = @_collection.where(attribute => value)
- columns.delete(associated)
+ next unless columns[associated]
+
+ if columns[associated][:as] == :belongs_to
+ if @_collection_apply_belongs_to && !@_collection.where_values_hash.include?(attribute)
+ @_collection = @_collection.where(attribute => value)
+ end
+
+ columns.delete(associated)
+ elsif columns[associated][:as] == :belongs_to_polymorphic
+ associated_type = attributes["#{associated}_type".to_sym] || raise("Expected #{associated}_type attribute to be present when #{associated}_id is present on a polymorphic belongs to")
+
+ if @_collection_apply_belongs_to
+ if !@_collection.where_values_hash.include?(attribute) && !@_collection.where_values_hash.include?("#{associated}_type")
+ @_collection = @_collection.where(attribute => value).where("#{associated}_type" => associated_type)
+ end
+ end
+
+ columns.delete(associated)
+ end
+
end.present?
load_columns! if changed
end