Class: Netzke::Basepack::DataAdapters::ActiveRecordAdapter
- Inherits:
-
AbstractAdapter
- Object
- AbstractAdapter
- Netzke::Basepack::DataAdapters::ActiveRecordAdapter
- Defined in:
- lib/netzke/basepack/data_adapters/active_record_adapter.rb
Class Method Summary collapse
Instance Method Summary collapse
-
#apply_column_filters(relation, column_filter) ⇒ Object
Parses and applies grid column filters, calling consequent “where” methods on the passed relation.
-
#assoc_and_assoc_method_for_attr(column_name) ⇒ Object
Returns association and association method for a column.
-
#class_for(assoc_name) ⇒ Object
Returns the model class for association columns.
- #column_virtual?(c) ⇒ Boolean
-
#combobox_options_for_column(column, method_options = {}) ⇒ Object
Returns options for comboboxes in grids/forms.
- #count_records(params, columns = []) ⇒ Object
- #destroy(ids) ⇒ Object
- #find_record(id) ⇒ Object
- #foreign_key_for(assoc_name) ⇒ Object
- #get_assoc_property_type(assoc_name, prop_name) ⇒ Object
- #get_records(params, columns = []) ⇒ Object
-
#get_relation(params = {}) ⇒ Object
An ActiveRecord::Relation instance encapsulating all the necessary conditions.
-
#hash_fk_model ⇒ Object
Build a hash of foreign keys and the associated model.
- #move_records(params) ⇒ Object
- #predicates_for_and_conditions(conditions) ⇒ Object
Methods inherited from AbstractAdapter
adapter_class, #errors_array, #first, #get_property_type, inherited, #initialize, #map_type, #new_record, #save_record
Constructor Details
This class inherits a constructor from Netzke::Basepack::DataAdapters::AbstractAdapter
Class Method Details
.for_class?(model_class) ⇒ Boolean
3 4 5 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 3 def self.for_class?(model_class) model_class <= ActiveRecord::Base end |
Instance Method Details
#apply_column_filters(relation, column_filter) ⇒ Object
Parses and applies grid column filters, calling consequent “where” methods on the passed relation. Returns the updated relation.
Example column grid data:
{"0" => {
"data" => {
"type" => "numeric",
"comparison" => "gt",
"value" => 10 },
"field" => "id"
},
"1" => {
"data" => {
"type" => "string",
"value" => "pizza"
},
"field" => "food_name"
}}
This will result in:
relation.where(["id > ?", 10]).where(["food_name like ?", "%pizza%"])
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 221 def apply_column_filters(relation, column_filter) res = relation operator_map = {"lt" => "<", "gt" => ">", "eq" => "="} # these are still JSON-encoded due to the migration to Ext.direct column_filter=JSON.parse(column_filter) column_filter.each do |v| assoc, method = v["field"].split('__') if method assoc = @model_class.reflect_on_association(assoc.to_sym) field = [assoc.klass.table_name, method].join('.').to_sym else field = assoc.to_sym end value = v["value"] op = operator_map[v['comparison']] case v["type"] when "string" res = res.where(["#{field} like ?", "%#{value}%"]) when "date" # convert value to the DB date value.match /(\d\d)\/(\d\d)\/(\d\d\d\d)/ res = res.where("#{field} #{op} ?", "#{$3}-#{$1}-#{$2}") when "numeric" res = res.where(["#{field} #{op} ?", value]) else res = res.where(["#{field} = ?", value]) end end res end |
#assoc_and_assoc_method_for_attr(column_name) ⇒ Object
Returns association and association method for a column
159 160 161 162 163 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 159 def assoc_and_assoc_method_for_attr(column_name) assoc_name, assoc_method = column_name.split('__') assoc = @model_class.reflect_on_association(assoc_name.to_sym) if assoc_method [assoc, assoc_method] end |
#class_for(assoc_name) ⇒ Object
Returns the model class for association columns
124 125 126 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 124 def class_for assoc_name @model_class.reflect_on_association(assoc_name.to_sym).klass end |
#column_virtual?(c) ⇒ Boolean
64 65 66 67 68 69 70 71 72 73 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 64 def column_virtual? c assoc_name, asso = c[:name].split('__') assoc, assoc_method = assoc_and_assoc_method_for_attr(c[:name]) if assoc return !assoc.klass.column_names.map(&:to_sym).include?(assoc_method.to_sym) else return !@model_class.column_names.map(&:to_sym).include?(c[:name].to_sym) end end |
#combobox_options_for_column(column, method_options = {}) ⇒ Object
Returns options for comboboxes in grids/forms
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 76 def (column, = {}) query = [:query] # First, check if we have options for this column defined in persistent storage = column[:combobox_options] && column[:combobox_options].split("\n") if query ? .select{ |o| o.index(/^#{query}/) }.map{ |el| [el] } : else assoc, assoc_method = assoc_and_assoc_method_for_attr(column[:name]) if assoc # Options for an asssociation attribute relation = assoc.klass.scoped relation = relation.extend_with([:scope]) if [:scope] if assoc.klass.column_names.include?(assoc_method) # apply query relation = relation.where(["#{assoc_method} like ?", "%#{query}%"]) if query.present? relation.all.map{ |r| [r.id, r.send(assoc_method)] } else relation.all.map{ |r| [r.id, r.send(assoc_method)] }.select{ |id,value| value =~ /^#{query}/ } end else # Options for a non-association attribute res=@model_class.(column[:name], ) # ensure it is an array-in-array, as Ext will fail otherwise raise RuntimeError, "netzke_combo_options_for should return an Array" unless res.kind_of? Array return [[]] if res.empty? unless res.first.kind_of? Array res=res.map do |v| [v] end end return res end end end |
#count_records(params, columns = []) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 44 def count_records(params, columns=[]) # build initial relation based on passed params relation = get_relation(params) # addressing the n+1 query problem columns.each do |c| assoc, method = c[:name].split('__') relation = relation.includes(assoc.to_sym) if method end relation.count end |
#destroy(ids) ⇒ Object
128 129 130 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 128 def destroy(ids) @model_class.destroy(ids) end |
#find_record(id) ⇒ Object
132 133 134 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 132 def find_record(id) @model_class.where(@model_class.primary_key => id).first end |
#foreign_key_for(assoc_name) ⇒ Object
119 120 121 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 119 def foreign_key_for assoc_name @model_class.reflect_on_association(assoc_name.to_sym).foreign_key end |
#get_assoc_property_type(assoc_name, prop_name) ⇒ Object
57 58 59 60 61 62 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 57 def get_assoc_property_type assoc_name, prop_name if prop_name && assoc=@model_class.reflect_on_association(assoc_name) assoc_column = assoc.klass.columns_hash[prop_name.to_s] assoc_column.try(:type) end end |
#get_records(params, columns = []) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 7 def get_records(params, columns=[]) # build initial relation based on passed params relation = get_relation(params) # addressing the n+1 query problem columns.each do |c| assoc, method = c[:name].split('__') relation = relation.includes(assoc.to_sym) if method end # apply sorting if needed if params[:sort] && sort_params = params[:sort].first assoc, method = sort_params["property"].split('__') dir = sort_params["direction"].downcase # if a sorting scope is set, call the scope with the given direction column = columns.detect { |c| c[:name] == sort_params["property"] } if column.has_key?(:sorting_scope) relation = relation.send(column[:sorting_scope].to_sym, dir.to_sym) else relation = if method.nil? relation.order("#{assoc} #{dir}") else assoc = @model_class.reflect_on_association(assoc.to_sym) relation.joins(assoc.name).order("#{assoc.klass.table_name}.#{method} #{dir}") end end end page = params[:limit] ? params[:start].to_i/params[:limit].to_i + 1 : 1 if params[:limit] relation.offset(params[:start]).limit(params[:limit]) else relation.all end end |
#get_relation(params = {}) ⇒ Object
An ActiveRecord::Relation instance encapsulating all the necessary conditions.
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 167 def get_relation(params = {}) @arel = @model_class.arel_table relation = @model_class.scoped relation = apply_column_filters(relation, params[:filter]) if params[:filter] if params[:extra_conditions] extra_conditions = normalize_extra_conditions(ActiveSupport::JSON.decode(params[:extra_conditions])) relation = relation.extend_with_netzke_conditions(extra_conditions) if params[:extra_conditions] end query = params[:query] && ActiveSupport::JSON.decode(params[:query]) if query.present? # array of arrays of conditions that should be joined by OR and_predicates = query.map do |conditions| predicates_for_and_conditions(conditions) end # join them by OR predicates = and_predicates[1..-1].inject(and_predicates.first){ |r,c| r.or(c) } end relation = relation.where(predicates) relation = relation.extend_with(params[:scope]) if params[:scope] relation end |
#hash_fk_model ⇒ Object
Build a hash of foreign keys and the associated model
137 138 139 140 141 142 143 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 137 def hash_fk_model foreign_keys = {} @model_class.reflect_on_all_associations(:belongs_to).map{ |r| foreign_keys[r.association_foreign_key.to_sym] = r.name } foreign_keys end |
#move_records(params) ⇒ Object
145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 145 def move_records(params) if defined?(ActsAsList) && @model_class.ancestors.include?(ActsAsList::InstanceMethods) ids = JSON.parse(params[:ids]).reverse ids.each_with_index do |id, i| r = @model_class.find(id) r.insert_at(params[:new_index].to_i + i + 1) end on_data_changed else raise RuntimeError, "Model class should implement 'acts_as_list' to support reordering records" end end |
#predicates_for_and_conditions(conditions) ⇒ Object
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/netzke/basepack/data_adapters/active_record_adapter.rb', line 257 def predicates_for_and_conditions(conditions) return nil if conditions.empty? predicates = conditions.map do |q| value = q["value"] case q["operator"] when "contains" @arel[q["attr"]].matches "%#{value}%" else if value == false || value == true @arel[q["attr"]].eq(value ? 1 : 0) else @arel[q["attr"]].send(q["operator"], value) end end end # join them by AND predicates[1..-1].inject(predicates.first){ |r,p| r.and(p) } end |