effective_resources 2.1.4 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c6a9d06e7d62a4fa96c365b8e6386d4229585ed5c0963b3f55b435ed4b7cbf4
4
- data.tar.gz: 84459f1187673d432756a4e3fccf6b163f3b5f55af26a7c1c485938e892d9e95
3
+ metadata.gz: 570e952fca070a0e231d90c8f959a80055d6a32e0b1ec51e93ae9c88d90fd44a
4
+ data.tar.gz: c7b247bfb4f12f6368405ac21f0a8591dc5e000d3f4a02c2daf728489d171128
5
5
  SHA512:
6
- metadata.gz: f76ef089d1b702f51948cf5ec7b03fc8fe9529428190225b9e27bddbc91c83c3e8d9b01911a2ae5d97efcae22cd8e2f77dd0d642b32b5184b459a6ccb4e3bbfa
7
- data.tar.gz: 6e13de73624c865c3312d2af94816890769599ed2aa1d89e4cde5251d545d25583a14293b04d2a152cc493c2c6c222015cba326e09dec19310771668bda2b8ab
6
+ metadata.gz: eb7ee9c3d1be22a10ad2b2d2b24e21a4af3bb084f8bdf07b484f67922ea68553bb31410562029e6b762076eec1bd6bf9eb510734c3c2c35f4c31d768479443a9
7
+ data.tar.gz: 1e905d78f87ddac0bfb423ad153c1066f9925739bf7f454296b9554c6c4ef6ff4a147b125f98b1a0cddeab61bfaa7e2f710d0121e7376ca7f03b62e2e7b9a09c
@@ -68,6 +68,7 @@ module ActsAsPurchasableWizard
68
68
  order.billing_address = owner.billing_address if owner.try(:billing_address).present?
69
69
 
70
70
  # Important to add/remove anything
71
+ # This will update the prices, but the purchasables must be persisted
71
72
  order.save!
72
73
 
73
74
  order
@@ -73,13 +73,13 @@ module Effective
73
73
  { as: :string }
74
74
  else
75
75
  if res.klass.unscoped.respond_to?(:datatables_scope)
76
- { collection: res.klass.datatables_scope.map { |obj| [obj.to_s, obj.to_param] } }
76
+ { collection: res.klass.datatables_scope.map { |obj| [obj.to_s, obj.id] } }
77
77
  elsif res.klass.unscoped.respond_to?(:datatables_filter)
78
- { collection: res.klass.datatables_filter.map { |obj| [obj.to_s, obj.to_param] } }
78
+ { collection: res.klass.datatables_filter.map { |obj| [obj.to_s, obj.id] } }
79
79
  elsif res.klass.unscoped.respond_to?(:sorted)
80
- { collection: res.klass.sorted.map { |obj| [obj.to_s, obj.to_param] } }
80
+ { collection: res.klass.sorted.map { |obj| [obj.to_s, obj.id] } }
81
81
  else
82
- { collection: res.klass.all.map { |obj| [obj.to_s, obj.to_param] }.sort { |x, y| x[0] <=> y[0] } }
82
+ { collection: res.klass.all.map { |obj| [obj.to_s, obj.id] }.sort { |x, y| x[0] <=> y[0] } }
83
83
  end
84
84
  end
85
85
  end
@@ -65,125 +65,274 @@ module Effective
65
65
  end
66
66
  end
67
67
 
68
- def search(name, value, as: nil, fuzzy: true, sql_column: nil)
68
+ def search(name, value, as: nil, column: nil, operation: nil)
69
69
  raise 'expected relation to be present' unless relation
70
70
 
71
- sql_column ||= sql_column(name)
72
- sql_type = (as || sql_type(name))
73
- fuzzy = true unless fuzzy == false
71
+ sql_as = (as || sql_type(name))
72
+ sql_column = (column || sql_column(name))
73
+ sql_operation = (operation || sql_operation(name, as: sql_as)).to_sym
74
74
 
75
75
  if ['SUM(', 'COUNT(', 'MAX(', 'MIN(', 'AVG('].any? { |str| sql_column.to_s.include?(str) }
76
76
  return relation.having("#{sql_column} = ?", value)
77
77
  end
78
78
 
79
- association = associated(name)
80
-
81
- term = Effective::Attribute.new(sql_type, klass: (association.try(:klass) rescue nil) || klass).parse(value, name: name)
82
-
83
- # term == 'nil' rescue false is a Rails 4.1 fix, where you can't compare a TimeWithZone to 'nil'
84
- if (term == 'nil' rescue false) && ![:has_and_belongs_to_many, :has_many, :has_one, :belongs_to, :belongs_to_polymorphic, :effective_roles].include?(sql_type)
85
- return relation.where(is_null(sql_column))
79
+ case sql_as
80
+ when :belongs_to, :belongs_to_polymorphic, :has_and_belongs_to_many, :has_many, :has_one
81
+ search_associated(name, value, as: sql_as, operation: sql_operation)
82
+ else
83
+ return relation.where(is_null(sql_column)) if value.to_s == 'nil'
84
+ search_attribute(name, value, as: sql_as, operation: sql_operation)
86
85
  end
86
+ end
87
87
 
88
- case sql_type
89
- when :belongs_to
90
- if term == 'nil'
91
- relation.where(is_null(association.foreign_key))
92
- else
93
- relation.where(search_by_associated_conditions(association, term, fuzzy: fuzzy))
94
- end
95
- when :belongs_to_polymorphic
96
- (type, id) = term.split('_')
97
-
98
- if term == 'nil'
99
- relation.where(is_null("#{sql_column}_id")).where(is_null("#{sql_column}_type"))
100
- elsif type.present? && id.present? # This was from a polymorphic select
101
- relation.where("#{sql_column}_id = ?", id).where("#{sql_column}_type = ?", type)
88
+ def search_associated(name, value, as:, operation:)
89
+ reflection = associated(name)
90
+ raise("expected to find #{relation.klass.name} #{name} reflection") unless reflection
91
+ raise("expected association operation") unless [:eq, :matches, :does_not_match, :sql].include?(operation)
92
+
93
+ # Parse values
94
+ value_ids = value.kind_of?(Array) ? value : (value.to_s.split(/,|\s|\|/) - [nil, '', ' '])
95
+ value_sql = Arel.sql(value) if value.kind_of?(String)
96
+
97
+ # Foreign id and type
98
+ foreign_id = reflection.foreign_key
99
+ foreign_type = reflection.foreign_key.to_s.chomp('_id') + '_type'
100
+
101
+ # belongs_to polymorphic
102
+ retval = if as == :belongs_to_polymorphic
103
+ (type, id) = value.to_s.split('_')
104
+
105
+ if type.present? && id.present? # This was from a polymorphic select
106
+ case operation
107
+ when :eq
108
+ relation.where(foreign_type => type, foreign_id => id)
109
+ when :matches
110
+ relation.where(foreign_type => type, foreign_id => id)
111
+ when :does_not_match
112
+ relation.where.not(foreign_type => type, foreign_id => id)
113
+ when :sql
114
+ if (relation.where(value_sql).present? rescue :invalid) != :invalid
115
+ relation.where(value_sql)
116
+ else
117
+ relation
118
+ end
119
+ end
102
120
  else # Maybe from a string field
103
- collection = relation.none
121
+ associated = relation.none
104
122
 
105
- relation.unscoped.distinct("#{name}_type").pluck("#{name}_type").each do |klass_name|
123
+ relation.unscoped.distinct(foreign_type).pluck(foreign_type).each do |klass_name|
106
124
  next if klass_name.nil?
107
125
 
108
126
  resource = Effective::Resource.new(klass_name)
109
127
  next unless resource.klass.present?
110
128
 
111
- collection = collection.or(relation.where("#{name}_id": resource.search_any(term, fuzzy: fuzzy), "#{name}_type": klass_name))
129
+ associated = associated.or(relation.where(foreign_id => resource.search_any(value), foreign_type => klass_name))
112
130
  end
113
131
 
114
- collection
115
- end
116
- when :has_and_belongs_to_many, :has_many, :has_one
117
- relation.where(search_by_associated_conditions(association, term, fuzzy: fuzzy))
118
- when :effective_addresses
119
- relation.where(id: Effective::Resource.new(association).search_any(value, fuzzy: fuzzy).pluck(:addressable_id))
120
- when :effective_obfuscation
121
- # If value == term, it's an invalid deobfuscated id
122
- relation.where("#{sql_column} = ?", (value == term ? 0 : term))
123
- when :effective_roles
124
- relation.with_role(term)
125
- when :active_storage
126
- relation.send("with_attached_#{name}").references("#{name}_attachment")
127
- .where(ActiveStorage::Blob.arel_table[:filename].matches("%#{term}%"))
128
- when :boolean
129
- relation.where("#{sql_column} = ?", term)
130
- when :datetime, :date
131
- end_at = (
132
- case (value.to_s.scan(/(\d+)/).flatten).length
133
- when 1 ; term.end_of_year # Year
134
- when 2 ; term.end_of_month # Year-Month
135
- when 3 ; term.end_of_day # Year-Month-Day
136
- when 4 ; term.end_of_hour # Year-Month-Day Hour
137
- when 5 ; term.end_of_minute # Year-Month-Day Hour-Minute
138
- when 6 ; term + 1.second # Year-Month-Day Hour-Minute-Second
139
- else term
132
+ case operation
133
+ when :eq
134
+ relation.where(id: associated.select(:id))
135
+ when :matches
136
+ relation.where(id: associated.select(:id))
137
+ when :does_not_match
138
+ relation.where.not(id: associated.select(:id))
139
+ when :sql
140
+ if (relation.where(value_sql).present? rescue :invalid) != :invalid
141
+ relation.where(value_sql)
142
+ else
143
+ relation
144
+ end
140
145
  end
141
- )
142
- relation.where("#{sql_column} >= ? AND #{sql_column} <= ?", term, end_at)
143
- when :time
144
- timed = relation.where("EXTRACT(hour from #{sql_column}) = ?", term.utc.hour)
145
- timed = timed.where("EXTRACT(minute from #{sql_column}) = ?", term.utc.min) if term.min > 0
146
- timed
147
- when :decimal, :currency
148
- if fuzzy && (term.round(0) == term) && value.to_s.include?('.') == false
149
- if term < 0
150
- relation.where("#{sql_column} <= ? AND #{sql_column} > ?", term, term-1.0)
146
+ end
147
+
148
+ # belongs_to non-polymorphic
149
+ elsif as == :belongs_to
150
+ foreign_collection = reflection.klass.all
151
+ foreign_collection = reflection.klass.where(foreign_type => relation.klass.name) if reflection.klass.new.respond_to?(foreign_type)
152
+
153
+ case operation
154
+ when :eq
155
+ associated = foreign_collection.where(id: value_ids)
156
+ relation.where(foreign_id => associated.select(:id))
157
+ when :matches
158
+ associated = Resource.new(foreign_collection).search_any(value)
159
+ relation.where(foreign_id => associated.select(:id))
160
+ when :does_not_match
161
+ associated = Resource.new(foreign_collection).search_any(value)
162
+ relation.where.not(foreign_id => associated.select(:id))
163
+ when :sql
164
+ if (foreign_collection.where(value_sql).present? rescue :invalid) != :invalid
165
+ associated = foreign_collection.where(value_sql)
166
+ relation.where(foreign_id => associated.select(:id))
151
167
  else
152
- relation.where("#{sql_column} >= ? AND #{sql_column} < ?", term, term+1.0)
168
+ relation
153
169
  end
154
- else
155
- relation.where("#{sql_column} = ?", term)
156
170
  end
157
- when :duration
158
- if fuzzy && (term % 60 == 0) && value.to_s.include?('m') == false
159
- if term < 0
160
- relation.where("#{sql_column} <= ? AND #{sql_column} > ?", term, term-60)
171
+
172
+ # has_and_belongs_to_many
173
+ elsif as == :has_and_belongs_to_many
174
+ foreign_collection = reflection.source_reflection.klass.all
175
+
176
+ habtm = foreign_collection.klass.reflect_on_all_associations.find { |ass| ass.macro == :has_and_belongs_to_many && ass.join_table == reflection.join_table }
177
+ raise("expected a matching HABTM reflection") unless habtm
178
+
179
+ case operation
180
+ when :eq
181
+ associated = foreign_collection.where(id: value_ids)
182
+ relation.where(id: associated.joins(habtm.name).select(foreign_id))
183
+ when :matches
184
+ associated = Resource.new(foreign_collection).search_any(value)
185
+ relation.where(id: associated.joins(habtm.name).select(foreign_id))
186
+ when :does_not_match
187
+ associated = Resource.new(foreign_collection).search_any(value)
188
+ relation.where.not(id: associated.joins(habtm.name).select(foreign_id))
189
+ when :sql
190
+ if (foreign_collection.where(value_sql).present? rescue :invalid) != :invalid
191
+ associated = foreign_collection.where(value_sql)
192
+ relation.where(id: associated.joins(habtm.name).select(foreign_id))
161
193
  else
162
- relation.where("#{sql_column} >= ? AND #{sql_column} < ?", term, term+60)
194
+ relation
163
195
  end
196
+ end
197
+
198
+ # has_many through
199
+ elsif reflection.options[:through].present?
200
+ reflected_klass = if reflection.source_reflection.options[:polymorphic]
201
+ reflection.klass
164
202
  else
165
- relation.where("#{sql_column} = ?", term)
203
+ reflection.source_reflection.klass
166
204
  end
167
- when :integer
168
- relation.where("#{sql_column} = ?", term)
169
- when :percent
170
- relation.where("#{sql_column} = ?", term)
171
- when :price
172
- relation.where("#{sql_column} = ?", term)
173
- when :string, :text, :email
174
- if fuzzy
175
- relation.where("#{sql_column} #{ilike} ?", "%#{term}%")
205
+
206
+ reflected_id = if reflection.source_reflection.macro == :belongs_to
207
+ reflection.source_reflection.foreign_key # to do check this
176
208
  else
177
- relation.where("#{sql_column} = ?", term)
209
+ reflection.source_reflection.klass.primary_key # group_id
178
210
  end
179
- when :uuid
180
- if fuzzy
181
- relation.where("#{sql_column}::text #{ilike} ?", "%#{term}%")
211
+
212
+ foreign_id = if reflection.through_reflection.macro == :belongs_to
213
+ reflection.through_reflection.klass.primary_key # to do check this
182
214
  else
183
- relation.where("#{sql_column}::text = ?", term)
215
+ reflection.through_reflection.foreign_key # user_id
216
+ end
217
+
218
+ # Build the through collection
219
+ through = reflection.through_reflection.klass.all # group mates
220
+
221
+ if reflection.source_reflection.options[:polymorphic]
222
+ through = through.where(reflection.source_reflection.foreign_type => reflected_klass.name)
223
+ end
224
+
225
+ # Search the associated class
226
+ case operation
227
+ when :eq
228
+ associated = through.where(reflected_id => value_ids)
229
+ relation.where(id: associated.select(foreign_id))
230
+ when :matches
231
+ reflected = Resource.new(reflected_klass).search_any(value)
232
+ associated = through.where(reflected_id => reflected)
233
+ relation.where(id: associated.select(foreign_id))
234
+ when :does_not_match
235
+ reflected = Resource.new(reflected_klass).search_any(value)
236
+ associated = through.where(reflected_id => reflected)
237
+ relation.where.not(id: associated.select(foreign_id))
238
+ when :sql
239
+ if (reflected_klass.where(value_sql).present? rescue :invalid) != :invalid
240
+ reflected = reflected_klass.where(value_sql)
241
+ associated = through.where(reflected_id => reflected)
242
+ relation.where(id: associated.select(foreign_id))
243
+ else
244
+ relation
245
+ end
246
+ end
247
+
248
+ # has_many and has_one
249
+ elsif (as == :has_many || as == :has_one)
250
+ foreign_collection = reflection.klass.all
251
+ foreign_collection = reflection.klass.where(foreign_type => relation.klass.name) if reflection.klass.new.respond_to?(foreign_type)
252
+
253
+ case operation
254
+ when :eq
255
+ associated = foreign_collection.where(id: value_ids)
256
+ relation.where(id: associated.select(foreign_id))
257
+ when :matches
258
+ associated = Resource.new(foreign_collection).search_any(value)
259
+ relation.where(id: associated.select(foreign_id))
260
+ when :does_not_match
261
+ associated = Resource.new(foreign_collection).search_any(value)
262
+ relation.where.not(id: associated.select(foreign_id))
263
+ when :sql
264
+ if (foreign_collection.where(value_sql).present? rescue :invalid) != :invalid
265
+ associated = foreign_collection.where(value_sql)
266
+ relation.where(id: associated.select(foreign_id))
267
+ else
268
+ relation
269
+ end
184
270
  end
185
- else
186
- raise "unsupported sql type #{sql_type}"
271
+ end
272
+
273
+ retval || raise("unable to search associated #{as} #{operation} #{name} for #{value}")
274
+ end
275
+
276
+ def search_attribute(name, value, as:, operation:)
277
+ raise 'expected relation to be present' unless relation
278
+
279
+ attribute = relation.arel_table[name]
280
+
281
+ # Normalize the term.
282
+ # If you pass an email attribute it can return nil so we return the full value
283
+ term = Attribute.new(as).parse(value, name: name) || value
284
+
285
+ searched = case as
286
+ when :date, :datetime
287
+ if value.kind_of?(String)
288
+ end_at = (
289
+ case (value.to_s.scan(/(\d+)/).flatten).length
290
+ when 1 ; term.end_of_year # Year
291
+ when 2 ; term.end_of_month # Year-Month
292
+ when 3 ; term.end_of_day # Year-Month-Day
293
+ when 4 ; term.end_of_hour # Year-Month-Day Hour
294
+ when 5 ; term.end_of_minute # Year-Month-Day Hour-Minute
295
+ when 6 ; term + 1.second # Year-Month-Day Hour-Minute-Second
296
+ else term
297
+ end
298
+ )
299
+
300
+ relation.where(attribute.gteq(term)).where(attribute.lteq(end_at))
301
+ end
302
+
303
+ when :effective_obfuscation
304
+ term = Attribute.new(as, klass: (associated(name).try(:klass) || klass)).parse(value, name: name)
305
+ relation.where(attribute.eq((value == term ? 0 : term)))
306
+
307
+ when :effective_addresses
308
+ association = associated(name)
309
+ associated = Resource.new(association).search_any(value)
310
+ relation.where(id: associated.where(addressable_type: klass.name).select(:addressable_id))
311
+
312
+ when :effective_roles
313
+ relation.with_role(term)
314
+
315
+ when :time
316
+ timed = relation.where("EXTRACT(hour from #{sql_column}) = ?", term.utc.hour)
317
+ timed = timed.where("EXTRACT(minute from #{sql_column}) = ?", term.utc.min) if term.min > 0
318
+ timed
319
+ end
320
+
321
+ return searched if searched
322
+
323
+ # Simple operation search
324
+ case operation
325
+ when :eq then relation.where(attribute.eq(term))
326
+ when :not_eq then relation.where(attribute.not_eq(term))
327
+ when :matches then relation.where(attribute.matches("%#{term}%"))
328
+ when :does_not_match then relation.where(attribute.does_not_match("%#{term}%"))
329
+ when :starts_with then relation.where(attribute.matches("#{term}%"))
330
+ when :ends_with then relation.where(attribute.matches("%#{term}"))
331
+ when :gt then relation.where(attribute.gt(term))
332
+ when :gteq then relation.where(attribute.gteq(term))
333
+ when :lt then relation.where(attribute.lt(term))
334
+ when :lteq then relation.where(attribute.lteq(term))
335
+ else raise("Unexpected operation: #{operation}")
187
336
  end
188
337
  end
189
338
 
@@ -195,11 +344,6 @@ module Effective
195
344
  return relation.where(klass.primary_key => value)
196
345
  end
197
346
 
198
- # If the value is 3-something-like-this
199
- if (values = value.to_s.split('-')).length > 0 && (maybe_id = values.first).present?
200
- return relation.where(klass.primary_key => maybe_id) if (maybe_id.to_i.to_s == maybe_id)
201
- end
202
-
203
347
  # If the user specifies columns. Filter out invalid ones for this klass
204
348
  if columns.present?
205
349
  columns = Array(columns).map(&:to_s) - [nil, '']
@@ -238,81 +382,6 @@ module Effective
238
382
 
239
383
  private
240
384
 
241
- def search_by_associated_conditions(association, value, fuzzy: nil)
242
- resource = Effective::Resource.new(association)
243
-
244
- # Search the target model for its matching records / keys
245
- relation = resource.search_any(value, fuzzy: fuzzy)
246
-
247
- if association.options[:as] # polymorphic
248
- relation = relation.where(association.type => klass.name)
249
- end
250
-
251
- # key: the id, or associated_id on my table
252
- # keys: the ids themselves as per the target table
253
- if association.macro == :belongs_to && association.options[:polymorphic]
254
- key = sql_column(association.foreign_key)
255
- keys = relation.pluck((relation.klass.primary_key rescue nil))
256
- elsif association.macro == :belongs_to
257
- key = sql_column(association.foreign_key)
258
- keys = relation.pluck(association.klass.primary_key)
259
- elsif association.macro == :has_and_belongs_to_many
260
- key = sql_column(klass.primary_key)
261
- values = relation.pluck(association.source_reflection.klass.primary_key).uniq.compact
262
-
263
- keys = if value == 'nil'
264
- klass.where.not(klass.primary_key => klass.joins(association.name)).pluck(klass.primary_key)
265
- else
266
- klass.joins(association.name)
267
- .where(association.name => { association.source_reflection.klass.primary_key => values })
268
- .pluck(klass.primary_key)
269
- end
270
- elsif association.options[:through].present?
271
- scope = association.through_reflection.klass.all
272
-
273
- if association.source_reflection.options[:polymorphic]
274
- reflected_klass = association.klass
275
- scope = scope.where(association.source_reflection.foreign_type => reflected_klass.name)
276
- else
277
- reflected_klass = association.source_reflection.klass
278
- end
279
-
280
- if association.through_reflection.macro == :belongs_to
281
- key = association.through_reflection.foreign_key
282
- pluck_key = association.through_reflection.klass.primary_key
283
- else
284
- key = sql_column(klass.primary_key)
285
- pluck_key = association.through_reflection.foreign_key
286
- end
287
-
288
- if value == 'nil'
289
- keys = klass.where.not(klass.primary_key => scope.pluck(pluck_key)).pluck(klass.primary_key)
290
- else
291
- keys = scope.where(association.source_reflection.foreign_key => relation).pluck(pluck_key)
292
- end
293
-
294
- elsif association.macro == :has_many
295
- key = sql_column(klass.primary_key)
296
-
297
- keys = if value == 'nil'
298
- klass.where.not(klass.primary_key => resource.klass.pluck(association.foreign_key)).pluck(klass.primary_key)
299
- else
300
- relation.pluck(association.foreign_key)
301
- end
302
-
303
- elsif association.macro == :has_one
304
- key = sql_column(klass.primary_key)
305
-
306
- keys = if value == 'nil'
307
- klass.where.not(klass.primary_key => resource.klass.pluck(association.foreign_key)).pluck(klass.primary_key)
308
- else
309
- relation.pluck(association.foreign_key)
310
- end
311
- end
312
-
313
- "#{key} IN (#{(keys.uniq.compact.presence || [0]).join(',')})"
314
- end
315
-
316
385
  def order_by_associated_conditions(association, sort: nil, direction: :asc, limit: nil)
317
386
  resource = Effective::Resource.new(association)
318
387
 
@@ -38,6 +38,15 @@ module Effective
38
38
  name.to_s.downcase == 'desc' ? 'DESC' : 'ASC'
39
39
  end
40
40
 
41
+ def sql_operation(name, as: nil)
42
+ sql_type = (as || sql_type(name))
43
+
44
+ case sql_type
45
+ when :boolean, :decimal, :integer, :price, :date, :datetime, :percent then :eq
46
+ else :matches
47
+ end
48
+ end
49
+
41
50
  # This is for EffectiveDatatables (col as:)
42
51
  # Might be :name, or 'users.name'
43
52
  def sql_type(name)
@@ -1,3 +1,3 @@
1
1
  module EffectiveResources
2
- VERSION = '2.1.4'.freeze
2
+ VERSION = '2.2.0'.freeze
3
3
  end
@@ -172,4 +172,10 @@ module EffectiveResources
172
172
 
173
173
  end
174
174
 
175
+ def self.replace_nested_attributes(attributes)
176
+ attributes.reject { |k, values| truthy?(values[:_destroy]) }.inject({}) do |h, (key, values)|
177
+ h[key] = values.reject { |k, v| k == 'id' || k == '_destroy' }; h
178
+ end
179
+ end
180
+
175
181
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_resources
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.4
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-29 00:00:00.000000000 Z
11
+ date: 2023-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails