Skip to content

Commit d7b62a8

Browse files
committed
Fix: Mongoid abstract model parsed values
1 parent 27fc68b commit d7b62a8

9 files changed

Lines changed: 64 additions & 53 deletions

File tree

lib/rails_admin/abstract_model.rb

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ def initialize_mongoid
111111
extend Adapters::Mongoid
112112
end
113113

114+
def parse_field_value(field, value)
115+
value.is_a?(Array) ? value.map { |v| field.parse_value(v) } : field.parse_value(value)
116+
end
117+
114118
class StatementBuilder
115119
def initialize(column, type, value, operator)
116120
@column = column
@@ -121,7 +125,6 @@ def initialize(column, type, value, operator)
121125

122126
def to_statement
123127
return if [@operator, @value].any? { |v| v == '_discard' }
124-
125128
unary_operators[@operator] || unary_operators[@value] ||
126129
build_statement_for_type_generic
127130
end
@@ -169,15 +172,15 @@ def build_statement_for_integer_decimal_or_float
169172

170173
def build_statement_for_date
171174
start_date, end_date = get_filtering_duration
172-
start_date = start_date.to_date if start_date
173-
end_date = end_date.to_date if end_date
175+
start_date = (start_date.to_date rescue nil) if start_date
176+
end_date = (end_date.to_date rescue nil) if end_date
174177
range_filter(start_date, end_date)
175178
end
176179

177180
def build_statement_for_datetime_or_timestamp
178181
start_date, end_date = get_filtering_duration
179-
start_date = start_date.to_time.beginning_of_day if start_date
180-
end_date = end_date.to_time.end_of_day if end_date
182+
start_date = start_date.to_time.try(:beginning_of_day) if start_date
183+
end_date = end_date.to_time.try(:end_of_day) if end_date
181184
range_filter(start_date, end_date)
182185
end
183186

lib/rails_admin/adapters/active_record.rb

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,8 @@ def filter_scope(scope, filters, fields = config.list.fields.select(&:filterable
131131
filters_dump.each do |_, filter_dump|
132132
wb = WhereBuilder.new(scope)
133133
field = fields.detect { |f| f.name.to_s == field_name }
134-
if filter_dump[:v].is_a?(Array)
135-
value = filter_dump[:v].map { |v| field.parse_value(v) }
136-
else
137-
value = field.parse_value(filter_dump[:v])
138-
end
134+
value = parse_field_value(field, filter_dump[:v])
135+
139136
wb.add(field, value, (filter_dump[:o] || 'default'))
140137
# AND current filter statements to other filter statements
141138
scope = wb.build

lib/rails_admin/adapters/mongoid.rb

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ module RailsAdmin
88
module Adapters
99
module Mongoid
1010
DISABLED_COLUMN_TYPES = ['Range', 'Moped::BSON::Binary', 'BSON::Binary', 'Mongoid::Geospatial::Point']
11-
ObjectId = defined?(Moped::BSON) ? Moped::BSON::ObjectId : BSON::ObjectId # rubocop:disable ConstantName
1211

1312
def new(params = {})
1413
AbstractObject.new(model.new(params))
@@ -67,9 +66,7 @@ def associations
6766

6867
def properties
6968
fields = model.fields.reject { |_name, field| DISABLED_COLUMN_TYPES.include?(field.type.to_s) }
70-
fields.collect do |_name, field|
71-
Property.new(field, model)
72-
end
69+
fields.collect { |_name, field| Property.new(field, model) }
7370
end
7471

7572
def table_name
@@ -102,6 +99,7 @@ def make_field_conditions(field, value, operator)
10299
conditions_per_collection = {}
103100
field.searchable_columns.each do |column_infos|
104101
collection_name, column_name = parse_collection_name(column_infos[:column])
102+
value = parse_field_value(field, value)
105103
statement = build_statement(column_name, column_infos[:type], value, operator)
106104
next unless statement
107105
conditions_per_collection[collection_name] ||= []
@@ -114,7 +112,8 @@ def query_conditions(query, fields = config.list.fields.select(&:queryable?))
114112
statements = []
115113

116114
fields.each do |field|
117-
conditions_per_collection = make_field_conditions(field, query, field.search_operator)
115+
value = parse_field_value(field, query)
116+
conditions_per_collection = make_field_conditions(field, value, field.search_operator)
118117
statements.concat make_condition_for_current_collection(field, conditions_per_collection)
119118
end
120119

@@ -134,7 +133,8 @@ def filter_conditions(filters, fields = config.list.fields.select(&:filterable?)
134133
filters_dump.each do |_, filter_dump|
135134
field = fields.detect { |f| f.name.to_s == field_name }
136135
next unless field
137-
conditions_per_collection = make_field_conditions(field, filter_dump[:v], (filter_dump[:o] || 'default'))
136+
value = parse_field_value(field, filter_dump[:v])
137+
conditions_per_collection = make_field_conditions(field, value, (filter_dump[:o] || 'default'))
138138
field_statements = make_condition_for_current_collection(field, conditions_per_collection)
139139
if field_statements.many?
140140
statements << {'$or' => field_statements}
@@ -265,8 +265,7 @@ def build_statement_for_enum
265265
end
266266

267267
def build_statement_for_belongs_to_association_or_bson_object_id
268-
object_id = (object_id_from_string(@value) rescue nil)
269-
{@column => object_id} if object_id
268+
{@column => @value} if @value
270269
end
271270

272271
def range_filter(min, max)
@@ -278,10 +277,6 @@ def range_filter(min, max)
278277
{@column => {'$lte' => max}}
279278
end
280279
end
281-
282-
def object_id_from_string(str)
283-
ObjectId.from_string(str)
284-
end
285280
end
286281
end
287282
end

lib/rails_admin/config/fields/types/bson_object_id.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'rails_admin/config/fields/types/string'
2+
require 'moped'
23

34
module RailsAdmin
45
module Config
@@ -7,6 +8,7 @@ module Types
78
class BsonObjectId < RailsAdmin::Config::Fields::Types::String
89
# Register field type for the type loader
910
RailsAdmin::Config::Fields::Types.register(self)
11+
OBJECT_ID = defined?(Moped::BSON) ? Moped::BSON::ObjectId : BSON::ObjectId
1012

1113
register_instance_option :label do
1214
label = ((@label ||= {})[::I18n.locale] ||= abstract_model.model.human_attribute_name name)
@@ -27,7 +29,9 @@ def generic_help
2729
end
2830

2931
def parse_value(value)
30-
value.present? ? abstract_model.object_id_from_string(value) : nil
32+
value.present? ? OBJECT_ID.from_string(value) : nil
33+
rescue BSON::ObjectId::Invalid
34+
nil
3135
rescue => e
3236
unless ['BSON::InvalidObjectId', 'Moped::Errors::InvalidObjectId'].include? e.class.to_s
3337
raise e

lib/rails_admin/config/fields/types/time.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ module Types
77
class Time < RailsAdmin::Config::Fields::Types::Datetime
88
RailsAdmin::Config::Fields::Types.register(self)
99

10+
def parse_value(value)
11+
super(value).try(:utc)
12+
end
13+
1014
register_instance_option :strftime_format do
1115
'%H:%M'
1216
end

spec/dummy_app/app/mongoid/field_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class FieldTest
1212
field :array_field, type: Array
1313
field :big_decimal_field, type: BigDecimal
1414
field :boolean_field, type: Boolean
15-
field :bson_object_id_field, type: RailsAdmin::Adapters::Mongoid::ObjectId
15+
field :bson_object_id_field, type: RailsAdmin::Config::Fields::Types::BsonObjectId::OBJECT_ID
1616
field :bson_binary_field, type: BSON::Binary
1717
field :date_field, type: Date
1818
field :datetime_field, type: DateTime

spec/rails_admin/adapters/mongoid_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,10 @@
348348
end
349349

350350
it 'supports datetime type query' do
351-
expect(@abstract_model.send(:filter_conditions, 'datetime_field' => {'1' => {v: ['', 'January 02, 2012', 'January 03, 2012'], o: 'between'}})).to eq('$and' => [{'datetime_field' => {'$gte' => Time.local(2012, 1, 2), '$lte' => Time.local(2012, 1, 3).end_of_day}}])
352-
expect(@abstract_model.send(:filter_conditions, 'datetime_field' => {'1' => {v: ['', 'January 03, 2012', ''], o: 'between'}})).to eq('$and' => [{'datetime_field' => {'$gte' => Time.local(2012, 1, 3)}}])
353-
expect(@abstract_model.send(:filter_conditions, 'datetime_field' => {'1' => {v: ['', '', 'January 02, 2012'], o: 'between'}})).to eq('$and' => [{'datetime_field' => {'$lte' => Time.local(2012, 1, 2).end_of_day}}])
354-
expect(@abstract_model.send(:filter_conditions, 'datetime_field' => {'1' => {v: ['January 02, 2012'], o: 'default'}})).to eq('$and' => [{'datetime_field' => {'$gte' => Time.local(2012, 1, 2), '$lte' => Time.local(2012, 1, 2).end_of_day}}])
351+
expect(@abstract_model.send(:filter_conditions, 'datetime_field' => {'1' => {v: ['', 'January 02, 2012 00:00', 'January 03, 2012 00:00'], o: 'between'}})).to eq('$and' => [{'datetime_field' => {'$gte' => Time.local(2012, 1, 2), '$lte' => Time.local(2012, 1, 3).end_of_day}}])
352+
expect(@abstract_model.send(:filter_conditions, 'datetime_field' => {'1' => {v: ['', 'January 03, 2012 00:00', ''], o: 'between'}})).to eq('$and' => [{'datetime_field' => {'$gte' => Time.local(2012, 1, 3)}}])
353+
expect(@abstract_model.send(:filter_conditions, 'datetime_field' => {'1' => {v: ['', '', 'January 02, 2012 00:00'], o: 'between'}})).to eq('$and' => [{'datetime_field' => {'$lte' => Time.local(2012, 1, 2).end_of_day}}])
354+
expect(@abstract_model.send(:filter_conditions, 'datetime_field' => {'1' => {v: ['January 02, 2012 00:00'], o: 'default'}})).to eq('$and' => [{'datetime_field' => {'$gte' => Time.local(2012, 1, 2), '$lte' => Time.local(2012, 1, 2).end_of_day}}])
355355
end
356356

357357
it 'supports enum type query' do

spec/rails_admin/config/fields/types/time_spec.rb

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,17 @@
44
it_behaves_like 'a generic field type', :time_field, :time
55

66
describe '#parse_input' do
7-
let(:field) { RailsAdmin.config(FieldTest).fields.detect { |f| f.name == :time_field } }
7+
let(:field) do
8+
RailsAdmin.config(FieldTest).fields.detect do |f|
9+
f.name == :time_field
10+
end
11+
end
12+
13+
before do
14+
RailsAdmin.config(FieldTest) do
15+
field :time_field, :time
16+
end
17+
end
818

919
before :each do
1020
@object = FactoryGirl.create(:field_test)
@@ -23,18 +33,28 @@
2333
it 'interprets time value as UTC when timezone is specified' do
2434
Time.zone = 'Eastern Time (US & Canada)' # -05:00
2535
@object.time_field = field.parse_input(time_field: @time.strftime('%H:%M'))
26-
expect(@object.time_field.strftime('%H:%M')).to eq(@time.strftime('%H:%M'))
36+
expect(@object.time_field.utc.strftime('%H:%M')).to eq(@time.strftime('%H:%M'))
2737
end
2838

29-
it 'has a customization option' do
30-
RailsAdmin.config FieldTest do
31-
field :time_field do
32-
strftime_format '%I:%M %p'
39+
context 'with a custom strftime_format' do
40+
let(:field) do
41+
RailsAdmin.config(FieldTest).fields.detect do |f|
42+
f.name == :time_field
3343
end
3444
end
3545

36-
@object.time_field = field.parse_input(time_field: @time.strftime('%I:%M %p'))
37-
expect(@object.time_field.strftime('%H:%M')).to eq(@time.strftime('%H:%M'))
46+
before do
47+
RailsAdmin.config(FieldTest) do
48+
field :time_field, :time do
49+
strftime_format '%I:%M %p'
50+
end
51+
end
52+
end
53+
54+
it 'has a customization option' do
55+
@object.time_field = field.parse_input(time_field: @time.strftime('%I:%M %p'))
56+
expect(@object.time_field.strftime('%H:%M')).to eq(@time.strftime('%H:%M'))
57+
end
3858
end
3959
end
4060
end

spec/spec_helper.rb

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ def password_digest(password)
6565

6666
config.include Capybara::DSL, type: :request
6767

68-
config.before do
68+
config.before do |example|
69+
DatabaseCleaner.strategy = (CI_ORM == :mongoid || example.metadata[:js]) ? :truncation : :transaction
70+
DatabaseCleaner.start
71+
6972
RailsAdmin::Config.reset
7073
RailsAdmin::AbstractModel.reset
7174
RailsAdmin::Config.audit_with(:history) if CI_ORM == :active_record
@@ -74,6 +77,7 @@ def password_digest(password)
7477

7578
config.after(:each) do
7679
Warden.test_reset!
80+
DatabaseCleaner.clean
7781
end
7882

7983
CI_TARGET_ORMS.each do |orm|
@@ -83,20 +87,4 @@ def password_digest(password)
8387
config.filter_run_excluding orm => true
8488
end
8589
end
86-
87-
# Configure Database Cleaner
88-
config.use_transactional_fixtures = false
89-
90-
config.before(:suite) do
91-
DatabaseCleaner.clean_with(:truncation)
92-
end
93-
94-
config.before(:each) do |example|
95-
DatabaseCleaner.strategy = (CI_ORM == :mongoid || example.metadata[:js]) ? :truncation : :transaction
96-
DatabaseCleaner.start
97-
end
98-
99-
config.after(:each) do
100-
DatabaseCleaner.clean
101-
end
10290
end

0 commit comments

Comments
 (0)