obitum-rails_admin 0.0.2 → 0.0.3

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.
Files changed (48) hide show
  1. data/app/assets/javascripts/rails_admin/ra.filter-box.js +33 -24
  2. data/app/assets/javascripts/rails_admin/ui.js.coffee +1 -1
  3. data/app/assets/stylesheets/rails_admin/aristo/jquery-ui-1.8.7.custom.css.scss +1 -1
  4. data/app/assets/stylesheets/rails_admin/base/theming.css.scss +5 -0
  5. data/app/controllers/rails_admin/main_controller.rb +16 -14
  6. data/app/helpers/rails_admin/application_helper.rb +1 -1
  7. data/app/helpers/rails_admin/form_builder.rb +7 -11
  8. data/app/views/layouts/rails_admin/application.html.haml +1 -1
  9. data/app/views/rails_admin/main/_form_filtering_multiselect.html.haml +4 -4
  10. data/app/views/rails_admin/main/_form_filtering_select.html.haml +4 -4
  11. data/app/views/rails_admin/main/_form_text.html.haml +1 -1
  12. data/app/views/rails_admin/main/index.html.haml +22 -6
  13. data/config/locales/fr.yml +24 -0
  14. data/config/locales/rails_admin.en.yml +1 -0
  15. data/lib/rails_admin/adapters/active_record.rb +45 -46
  16. data/lib/rails_admin/config/actions/edit.rb +7 -3
  17. data/lib/rails_admin/config/actions/index.rb +3 -1
  18. data/lib/rails_admin/config/actions/new.rb +4 -4
  19. data/lib/rails_admin/config/actions.rb +1 -1
  20. data/lib/rails_admin/config/fields/association.rb +19 -9
  21. data/lib/rails_admin/config/fields/base.rb +28 -39
  22. data/lib/rails_admin/config/fields/factories/belongs_to_association.rb +2 -2
  23. data/lib/rails_admin/config/fields/factories/carrierwave.rb +1 -1
  24. data/lib/rails_admin/config/fields/factories/enum.rb +1 -1
  25. data/lib/rails_admin/config/fields/factories/password.rb +1 -1
  26. data/lib/rails_admin/config/fields/factories/serialized.rb +17 -0
  27. data/lib/rails_admin/config/fields/types/all.rb +1 -0
  28. data/lib/rails_admin/config/fields/types/belongs_to_association.rb +6 -8
  29. data/lib/rails_admin/config/fields/types/boolean.rb +4 -2
  30. data/lib/rails_admin/config/fields/types/has_one_association.rb +5 -1
  31. data/lib/rails_admin/config/fields/types/hidden.rb +4 -2
  32. data/lib/rails_admin/config/fields/types/integer.rb +3 -1
  33. data/lib/rails_admin/config/fields/types/password.rb +2 -5
  34. data/lib/rails_admin/config/fields/types/polymorphic_association.rb +1 -1
  35. data/lib/rails_admin/config/fields/types/serialized.rb +22 -0
  36. data/lib/rails_admin/config/fields/types/string.rb +0 -2
  37. data/lib/rails_admin/config/fields/types/text.rb +1 -3
  38. data/lib/rails_admin/config/fields.rb +2 -1
  39. data/lib/rails_admin/config/groupable.rb +18 -0
  40. data/lib/rails_admin/config/has_fields.rb +1 -1
  41. data/lib/rails_admin/extensions/history/history.rb +1 -1
  42. data/lib/rails_admin/version.rb +1 -1
  43. data/spec/controllers/main_controller_spec.rb +67 -1
  44. data/spec/integration/basic/list/rails_admin_basic_list_spec.rb +2 -1
  45. data/spec/unit/adapters/active_record_spec.rb +22 -0
  46. data/spec/unit/config/actions_spec.rb +4 -0
  47. metadata +11 -193
  48. data/lib/rails_admin/config/fields/groupable.rb +0 -25
@@ -3,7 +3,15 @@
3
3
  var filters;
4
4
 
5
5
  $.filters = filters = {
6
- append: function(field_label, field_name, field_type, field_value, field_operator, field_options, multiple_values, index) {
6
+ options: {
7
+ regional: {
8
+ datePicker: {
9
+ dateFormat: 'mm/dd/yy'
10
+ }
11
+ }
12
+ },
13
+
14
+ append: function(field_label, field_name, field_type, field_value, field_operator, field_options, index) {
7
15
  var value_name = 'f[' + field_name + '][' + index + '][v]';
8
16
  var operator_name = 'f[' + field_name + '][' + index + '][o]';
9
17
  switch(field_type) {
@@ -21,22 +29,23 @@
21
29
  case 'datetime':
22
30
  case 'timestamp':
23
31
  var control = '<select class="switch-additionnal-fieldsets input-small" name="' + operator_name + '">' +
24
- '<option data-additional-fieldset="false" value="_discard">...</option>' +
25
- '<option data-additional-fieldset="false"' + (field_operator == "today" ? 'selected="selected"' : '') + ' value="today">Today</option>' +
26
- '<option data-additional-fieldset="false"' + (field_operator == "yesterday" ? 'selected="selected"' : '') + ' value="yesterday">Yesterday</option>' +
27
- '<option data-additional-fieldset="false"' + (field_operator == "this_week" ? 'selected="selected"' : '') + ' value="this_week">This week</option>' +
28
- '<option data-additional-fieldset="false"' + (field_operator == "last_week" ? 'selected="selected"' : '') + ' value="last_week">Last week</option>' +
29
- '<option data-additional-fieldset="true" ' + (field_operator == "less_than" ? 'selected="selected"' : '') + ' value="less_than">Less than ... days ago</option>' +
30
- '<option data-additional-fieldset="true" ' + (field_operator == "more_than" ? 'selected="selected"' : '') + ' value="more_than">More than ... days ago</option>' +
31
- '<option data-additional-fieldset="true" ' + (field_operator == "mmddyyyy" ? 'selected="selected"' : '') + ' value="mmddyyyy">On specific date (mmddyyyy)</option>' +
32
+ '<option ' + (field_operator == "default" ? 'selected="selected"' : '') + ' data-additional-fieldset="default" value="default">Date ...</option>' +
33
+ '<option ' + (field_operator == "between" ? 'selected="selected"' : '') + ' data-additional-fieldset="between" value="between">Between ... and ...</option>' +
34
+ '<option ' + (field_operator == "today" ? 'selected="selected"' : '') + ' value="today">Today</option>' +
35
+ '<option ' + (field_operator == "yesterday" ? 'selected="selected"' : '') + ' value="yesterday">Yesterday</option>' +
36
+ '<option ' + (field_operator == "this_week" ? 'selected="selected"' : '') + ' value="this_week">This week</option>' +
37
+ '<option ' + (field_operator == "last_week" ? 'selected="selected"' : '') + ' value="last_week">Last week</option>' +
32
38
  '<option disabled="disabled">---------</option>' +
33
- '<option data-additional-fieldset="false"' + (field_operator == "_not_null" ? 'selected="selected"' : '') + ' value="_not_null">Is present</option>' +
34
- '<option data-additional-fieldset="false"' + (field_operator == "_null" ? 'selected="selected"' : '') + ' value="_null" >Is blank</option>' +
39
+ '<option ' + (field_operator == "_not_null" ? 'selected="selected"' : '') + ' value="_not_null">Is present</option>' +
40
+ '<option ' + (field_operator == "_null" ? 'selected="selected"' : '') + ' value="_null" >Is blank</option>' +
35
41
  '</select>'
36
- var additional_control = '<input class="additional-fieldset input-small" style="display:' + (field_operator == "less_than" || field_operator == "more_than" || field_operator == "mmddyyyy" ? 'inline-block' : 'none') + ';" type="text" name="' + value_name + '" value="' + field_value + '" /> ';
42
+ var additional_control =
43
+ '<input class="date additional-fieldset default input-small" style="display:' + ((!field_operator || field_operator == "default") ? 'inline-block' : 'none') + ';" type="text" name="' + value_name + '[]" value="' + (field_value[0] || '') + '" /> ' +
44
+ '<input placeholder="-∞" class="date additional-fieldset between input-small" style="display:' + ((field_operator == "between") ? 'inline-block' : 'none') + ';" type="text" name="' + value_name + '[]" value="' + (field_value[1] || '') + '" /> ' +
45
+ '<input placeholder="∞" class="date additional-fieldset between input-small" style="display:' + ((field_operator == "between") ? 'inline-block' : 'none') + ';" type="text" name="' + value_name + '[]" value="' + (field_value[2] || '') + '" />';
37
46
  break;
38
47
  case 'enum':
39
- var field_options = $('<div/>').html(field_options).text(); // entities decode
48
+ var multiple_values = ((field_value instanceof Array) ? true : false)
40
49
  var control = '<select style="display:' + (multiple_values ? 'none' : 'inline-block') + '" ' + (multiple_values ? '' : 'name="' + value_name + '"') + ' data-name="' + value_name + '" class="select-single input-small">' +
41
50
  '<option value="_discard">...</option>' +
42
51
  '<option ' + (field_value == "_present" ? 'selected="selected"' : '') + ' value="_present">Is present</option>' +
@@ -53,13 +62,13 @@
53
62
  case 'text':
54
63
  case 'belongs_to_association':
55
64
  var control = '<select class="switch-additionnal-fieldsets input-small" value="' + field_operator + '" name="' + operator_name + '">' +
56
- '<option data-additional-fieldset="true"' + (field_operator == "like" ? 'selected="selected"' : '') + ' value="like">Contains</option>' +
57
- '<option data-additional-fieldset="true"' + (field_operator == "is" ? 'selected="selected"' : '') + ' value="is">Is exactly</option>' +
58
- '<option data-additional-fieldset="true"' + (field_operator == "starts_with" ? 'selected="selected"' : '') + ' value="starts_with">Starts with</option>' +
59
- '<option data-additional-fieldset="true"' + (field_operator == "ends_with" ? 'selected="selected"' : '') + ' value="ends_with">Ends with</option>' +
65
+ '<option data-additional-fieldset="additional-fieldset"' + (field_operator == "like" ? 'selected="selected"' : '') + ' value="like">Contains</option>' +
66
+ '<option data-additional-fieldset="additional-fieldset"' + (field_operator == "is" ? 'selected="selected"' : '') + ' value="is">Is exactly</option>' +
67
+ '<option data-additional-fieldset="additional-fieldset"' + (field_operator == "starts_with" ? 'selected="selected"' : '') + ' value="starts_with">Starts with</option>' +
68
+ '<option data-additional-fieldset="additional-fieldset"' + (field_operator == "ends_with" ? 'selected="selected"' : '') + ' value="ends_with">Ends with</option>' +
60
69
  '<option disabled="disabled">---------</option>' +
61
- '<option data-additional-fieldset="false"' + (field_operator == "_present" ? 'selected="selected"' : '') + ' value="_present">Is present</option>' +
62
- '<option data-additional-fieldset="false"' + (field_operator == "_blank" ? 'selected="selected"' : '') + ' value="_blank">Is blank</option>' +
70
+ '<option ' + (field_operator == "_present" ? 'selected="selected"' : '') + ' value="_present">Is present</option>' +
71
+ '<option ' + (field_operator == "_blank" ? 'selected="selected"' : '') + ' value="_blank">Is blank</option>' +
63
72
  '</select>'
64
73
  var additional_control = '<input class="additional-fieldset input-small" style="display:' + (field_operator == "_blank" || field_operator == "_present" ? 'none' : 'inline-block') + ';" type="text" name="' + value_name + '" value="' + field_value + '" /> ';
65
74
  break;
@@ -74,6 +83,7 @@
74
83
  (additional_control || '') +
75
84
  '</div> ';
76
85
  $('#filters_box').append(content);
86
+ $('#filters_box .date').datepicker(this.options.regional.datePicker);
77
87
  $("hr.filters_box:hidden").show('slow');
78
88
  }
79
89
  }
@@ -87,8 +97,7 @@
87
97
  $(this).data('field-value'),
88
98
  $(this).data('field-operator'),
89
99
  $(this).data('field-options'),
90
- $(this).data('field-multiple_values'),
91
- $.now().toString().slice(7,11)
100
+ $.now().toString().slice(6,11)
92
101
  );
93
102
  });
94
103
 
@@ -97,7 +106,6 @@
97
106
  form = $(this).parents('form');
98
107
  $(this).parents('.filter').remove();
99
108
  !$("#filters_box").children().length && $("hr.filters_box:visible").hide('slow');
100
- form.submit();
101
109
  });
102
110
 
103
111
  $('#filters_box .switch-select').live('click', function(e) {
@@ -111,8 +119,9 @@
111
119
 
112
120
  $('#filters_box .switch-additionnal-fieldsets').live('change', function() {
113
121
  var selected_option = $(this).find('option:selected');
114
- if($(selected_option).data('additional-fieldset')) {
115
- $(this).siblings('.additional-fieldset').show('slow');
122
+ if(klass = $(selected_option).data('additional-fieldset')) {
123
+ $(this).siblings('.additional-fieldset:not(.' + klass + ')').hide('slow');
124
+ $(this).siblings('.' + klass).show('slow');
116
125
  } else {
117
126
  $(this).siblings('.additional-fieldset').hide('slow');
118
127
  }
@@ -45,7 +45,7 @@ $('.form-horizontal legend').live 'click', ->
45
45
  if $(this).has('i.icon-chevron-right').length
46
46
  $(this).siblings('.control-group:hidden').show('slow')
47
47
  $(this).children('i').toggleClass('icon-chevron-down icon-chevron-right')
48
-
48
+
49
49
  $(document).ready ->
50
50
 
51
51
  $('.animate-width-to').each ->
@@ -385,7 +385,7 @@
385
385
  * http://docs.jquery.com/UI/Autocomplete#theming
386
386
  */
387
387
  .ui-autocomplete {
388
- position: absolute; cursor: default; z-index: 3;
388
+ position: absolute; cursor: default; z-index: 1051 !important;
389
389
  -moz-border-radius: 0;
390
390
  -webkit-border-radius: 0;
391
391
  border-radius: 0;
@@ -31,6 +31,11 @@ body.rails_admin {
31
31
 
32
32
  /* new/edit/export forms */
33
33
  .form-horizontal {
34
+ /* hide hidden fields controls by default */
35
+ .control-group .hidden_type {
36
+ display:none;
37
+ }
38
+
34
39
  legend {
35
40
  cursor:pointer;
36
41
  i {
@@ -69,18 +69,7 @@ module RailsAdmin
69
69
  reversed_sort = (field ? field.sort_reverse? : model_config.list.sort_reverse?)
70
70
  {:sort => column, :sort_reverse => (params[:sort_reverse] == reversed_sort.to_s)}
71
71
  end
72
-
73
- def get_attributes
74
- attributes = params[@abstract_model.to_param.gsub('~','_')] || {}
75
- attributes.each do |key, value|
76
- # Deserialize the attribute if attribute is serialized
77
- if @abstract_model.model.serialized_attributes.keys.include?(key) and value.is_a? String
78
- attributes[key] = YAML::load(value)
79
- end
80
- end
81
- attributes
82
- end
83
-
72
+
84
73
  def redirect_to_on_success
85
74
  notice = t("admin.flash.successful", :name => @model_config.label, :action => t("admin.actions.#{@action.key}.done"))
86
75
  if params[:_add_another]
@@ -92,6 +81,19 @@ module RailsAdmin
92
81
  end
93
82
  end
94
83
 
84
+ def sanitize_params_for!(action, model_config = @model_config, _params = params[@abstract_model.param_key])
85
+ return unless _params.present?
86
+ fields = model_config.send(action).fields
87
+ fields.select{ |f| f.respond_to?(:parse_input) }.each {|f| f.parse_input(_params) }
88
+
89
+ fields.select(&:nested_form).each do |association|
90
+ children_params = association.multiple? ? _params[association.method_name].try(:values) : [_params[association.method_name]].compact
91
+ (children_params || []).each do |children_param|
92
+ sanitize_params_for!(:nested, association.associated_model_config, children_param)
93
+ end
94
+ end
95
+ end
96
+
95
97
  def handle_save_error whereto = :new
96
98
  action = params[:action]
97
99
 
@@ -129,8 +131,8 @@ module RailsAdmin
129
131
  source_model_config = source_abstract_model.config
130
132
  source_object = source_abstract_model.get(params[:source_object_id])
131
133
  action = params[:current_action].in?(['create', 'update']) ? params[:current_action] : 'edit'
132
- association = source_model_config.send(action).fields.find{|f| f.name == params[:associated_collection].to_sym }.with(:controller => self, :object => source_object)
133
- association.associated_collection_scope
134
+ @association = source_model_config.send(action).fields.find{|f| f.name == params[:associated_collection].to_sym }.with(:controller => self, :object => source_object)
135
+ @association.associated_collection_scope
134
136
  end
135
137
 
136
138
  def associations_hash
@@ -109,7 +109,7 @@ module RailsAdmin
109
109
  return '' if actions.empty?
110
110
  content_tag :li, { :class => 'dropdown', :style => 'float:right' } do
111
111
  content_tag(:a, { :class => 'dropdown-toggle', :'data-toggle' => "dropdown", :href => '#' }) { t('admin.misc.bulk_menu_title').html_safe + '<b class="caret"></b>'.html_safe } +
112
- content_tag(:ul, :class => 'dropdown-menu') do
112
+ content_tag(:ul, :class => 'dropdown-menu', :style => 'left:auto; right:0;') do
113
113
  actions.map do |action|
114
114
  content_tag :li do
115
115
  link_to_function wording_for(:bulk_link, action), "jQuery('#bulk_action').val('#{action.action_name}'); jQuery('#bulk_form').submit()"
@@ -32,15 +32,11 @@ module RailsAdmin
32
32
  end
33
33
 
34
34
  def field_wrapper_for field, nested_in
35
- if field.is_a?(RailsAdmin::Config::Fields::Types::Hidden)
36
- input_for(field)
37
- else
38
- # do not show nested field if the target is the origin
39
- unless field.inverse_of.presence && field.inverse_of == nested_in
40
- @template.content_tag(:div, :class => "control-group #{field.type_css_class} #{field.css_class} #{'error' if field.errors.present?}", :id => "#{dom_id(field)}_field") do
41
- label(field.method_name, field.label, :class => 'control-label') +
42
- (field.nested_form ? field_for(field) : input_for(field))
43
- end
35
+ # do not show nested field if the target is the origin
36
+ unless field.inverse_of.presence && field.inverse_of == nested_in
37
+ @template.content_tag(:div, :class => "control-group #{field.type_css_class} #{field.css_class} #{'error' if field.errors.present?}", :id => "#{dom_id(field)}_field") do
38
+ label(field.method_name, field.label, :class => 'control-label') +
39
+ (field.nested_form ? field_for(field) : input_for(field))
44
40
  end
45
41
  end
46
42
  end
@@ -62,7 +58,7 @@ module RailsAdmin
62
58
  end
63
59
 
64
60
  def field_for field
65
- if field.read_only
61
+ if field.read_only?
66
62
  field.pretty_value.to_s.html_safe
67
63
  else
68
64
  field.render
@@ -102,7 +98,7 @@ module RailsAdmin
102
98
  end
103
99
 
104
100
  def dom_name field
105
- (@dom_name ||= {})[field.name] ||= %{#{@object_name}#{options[:index] && "[#{options[:index]}]"}[#{field.method_name}]#{field.is_a?(Config::Fields::Types::HasManyAssociation) ? '[]' : ''}}
101
+ (@dom_name ||= {})[field.name] ||= %{#{@object_name}#{options[:index] && "[#{options[:index]}]"}[#{field.method_name}]#{field.is_a?(Config::Fields::Association) && field.multiple? ? '[]' : ''}}
106
102
  end
107
103
  end
108
104
  end
@@ -5,7 +5,7 @@
5
5
  %meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"}
6
6
  %meta{:content => "NONE,NOARCHIVE", :name => "robots"}
7
7
  = csrf_meta_tag
8
- = stylesheet_link_tag "rails_admin/rails_admin.css"
8
+ = stylesheet_link_tag "rails_admin/rails_admin.css", :media => :all
9
9
  = javascript_include_tag "rails_admin/rails_admin.js"
10
10
  %body.rails_admin
11
11
  .navbar.navbar-fixed-top
@@ -8,7 +8,7 @@
8
8
  else
9
9
  selected = form.object.send(field.name)
10
10
  end
11
- selected_ids = selected.map(&:id)
11
+ selected_ids = selected.map{|s| s.send(field.associated_primary_key)}
12
12
 
13
13
 
14
14
  current_action = params[:action].in?(['create', 'new']) ? 'create' : 'update'
@@ -18,10 +18,10 @@
18
18
  xhr = !field.associated_collection_cache_all
19
19
 
20
20
  collection = if xhr
21
- selected.map { |o| [o.send(config.object_label_method), o.id] }
21
+ selected.map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }
22
22
  else
23
23
  i = 0
24
- controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(config.object_label_method), o.id] }.sort_by {|a| [selected_ids.index(a[1]) || selected_ids.size, i+=1] }
24
+ controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }.sort_by {|a| [selected_ids.index(a[1]) || selected_ids.size, i+=1] }
25
25
  end
26
26
 
27
27
  %input{:name => form.dom_name(field), :type => "hidden", :value => ""}
@@ -40,7 +40,7 @@
40
40
  createQuery: function(query) {
41
41
  return { query: query }
42
42
  },
43
- remote_source: "#{index_path(field.associated_model_config.abstract_model, :source_object_id => form.object.id, :source_abstract_model => source_abstract_model.to_param, :associated_collection => field.name, :current_action => current_action, :compact => true).html_safe}",
43
+ remote_source: "#{index_path(config.abstract_model, :source_object_id => form.object.id, :source_abstract_model => source_abstract_model.to_param, :associated_collection => field.name, :current_action => current_action, :compact => true).html_safe}",
44
44
  sortable: #{field.orderable ? 'true' : 'false'},
45
45
  cacheAll: #{field.associated_collection_cache_all ? 'true' : 'false'},
46
46
  regional: {
@@ -5,8 +5,8 @@
5
5
 
6
6
  if form.object.new_record? && related_id.present? && related_id != 'new'
7
7
  selected = config.abstract_model.get(related_id)
8
- selected_id = selected.id
9
- selected_name = selected.send(config.object_label_method)
8
+ selected_id = selected.send(field.associated_primary_key)
9
+ selected_name = selected.send(field.associated_object_label_method)
10
10
  else
11
11
  selected_id = field.selected_id
12
12
  selected_name = field.formatted_value
@@ -17,8 +17,8 @@
17
17
  edit_url = authorized?(:edit, config.abstract_model) ? edit_path(:model_name => config.abstract_model.to_param, :modal => true, :id => '__ID__') : ''
18
18
 
19
19
  xhr = !field.associated_collection_cache_all
20
-
21
- collection = xhr ? [[selected_name, selected_id]] : controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(config.object_label_method), o.id] }
20
+
21
+ collection = xhr ? [[selected_name, selected_id]] : controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }
22
22
 
23
23
  - selected_id = (hdv = field.html_default_value).nil? ? selected_id : hdv
24
24
  = form.select field.method_name, collection, { :selected => selected_id, :include_blank => true }, field.html_attributes.reverse_merge({:placeholder => t('admin.misc.search')})
@@ -1,4 +1,4 @@
1
- = form.send field.view_helper, field.method_name, field.html_attributes.reverse_merge((hdv = field.html_default_value).nil? ? {} : { :value => hdv })
1
+ = form.text_area field.method_name, field.html_attributes.reverse_merge((hdv = field.html_default_value).nil? ? { :value => field.formatted_value } : { :value => hdv })
2
2
 
3
3
  - if field.ckeditor
4
4
  = javascript_tag do
@@ -1,4 +1,5 @@
1
1
  :ruby
2
+ require 'rails_admin/config/fields/types/datetime.rb'
2
3
  query = params[:query]
3
4
  params = request.params.except(:authenticity_token, :action, :controller, :utf8, :bulk_export, :_pjax)
4
5
  params.delete(:query) if params[:query].blank?
@@ -38,12 +39,14 @@
38
39
  field = @filterable_fields.find{ |field| field.name == filter_name.to_sym }
39
40
  field_options = case field.type
40
41
  when :enum
41
- options_for_select(field.with(:object => @abstract_model.model.new).enum, filter_hash['v']).gsub("\n", '')
42
+ options_for_select(field.with(:object => @abstract_model.model.new).enum, filter_hash['v'])
42
43
  else
43
44
  ''
44
45
  end
45
- "$.filters.append('#{escape_javascript field.label.to_s}', '#{escape_javascript field.name.to_s}', '#{escape_javascript field.type.to_s}', '#{escape_javascript filter_hash['v'].to_s}', '#{escape_javascript filter_hash['o'].to_s}', '#{escape_javascript field_options.to_s}', #{filter_hash['v'].is_a?(Array)}, '#{escape_javascript filter_index.to_s}');"
46
- end.join if @ordered_filters
46
+ %{
47
+ $.filters.append(#{field.label.to_json}, #{field.name.to_json}, #{field.type.to_json}, #{filter_hash['v'].to_json}, #{filter_hash['o'].to_json}, #{field_options.to_json}, #{filter_index.to_json});
48
+ }
49
+ end.join.html_safe if @ordered_filters
47
50
 
48
51
 
49
52
  = content_for :contextual_tabs do
@@ -53,20 +56,33 @@
53
56
  %a.dropdown-toggle{:href => '#', :'data-toggle' => "dropdown"}
54
57
  = t('admin.misc.add_filter')
55
58
  %b.caret
56
- %ul.dropdown-menu#filters
59
+ %ul.dropdown-menu#filters{:style => 'left:auto; right:0;'}
57
60
  - @filterable_fields.each do |field|
58
61
  - field_options = case field.type
59
62
  - when :enum
60
- - h options_for_select(field.with(:object => @abstract_model.model.new).enum).gsub("\n", '')
63
+ - options_for_select(field.with(:object => @abstract_model.model.new).enum)
61
64
  - else
62
65
  - ''
63
66
  %li
64
- %a{:href => '#', "data-field-label" => field.label, "data-field-name" => field.name, "data-field-options" => field_options, "data-field-type" => field.type, "data-field-value" => ""}= field.label
67
+ %a{:href => '#', :"data-field-label" => field.label, :"data-field-name" => field.name, :"data-field-options" => field_options.html_safe, :"data-field-type" => field.type, :"data-field-value" => ""}= field.label
65
68
 
66
69
  #list{:'data-pjax-container' => true}
67
70
  %script
68
71
  jQuery(function($) {
72
+ $.filters.options.regional = {
73
+ datePicker: {
74
+ dateFormat: #{raw I18n.t("admin.misc.filter_date_format", :default => I18n.t("admin.misc.filter_date_format", :locale => :en)).to_json},
75
+ dayNames: #{raw RailsAdmin::Config::Fields::Types::Datetime.day_names.to_json},
76
+ dayNamesShort: #{raw RailsAdmin::Config::Fields::Types::Datetime.abbr_day_names.to_json},
77
+ dayNamesMin: #{raw RailsAdmin::Config::Fields::Types::Datetime.abbr_day_names.to_json},
78
+ firstDay: "1",
79
+ monthNames: #{raw RailsAdmin::Config::Fields::Types::Datetime.month_names.to_json},
80
+ monthNamesShort: #{raw RailsAdmin::Config::Fields::Types::Datetime.abbr_month_names.to_json},
81
+ }
82
+ }
83
+
69
84
  = @ordered_filter_string
85
+
70
86
  });
71
87
  %style
72
88
  - properties.select{ |p| p.column_width.present? }.each do |property|
@@ -0,0 +1,24 @@
1
+ fr:
2
+ date:
3
+ formats:
4
+ default: "%d/%m/%Y"
5
+ short: "%e %b"
6
+ compact: "%d/%m/%y"
7
+ long: "%e %B %Y"
8
+ day_names: [dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi]
9
+ abbr_day_names: [dim, lun, mar, mer, jeu, ven, sam]
10
+ month_names: [~, janvier, février, mars, avril, mai, juin, juillet, août, septembre, octobre, novembre, décembre]
11
+ abbr_month_names: [~, jan., fév., mar., avr., mai, juin, juil., août, sept., oct., nov., déc.]
12
+ order:
13
+ - :day
14
+ - :month
15
+ - :year
16
+ time:
17
+ formats:
18
+ default: "%d %B %Y %H:%M:%S"
19
+ short: "%d %b %H:%M"
20
+ compact: "%d/%m/%y %H:%M"
21
+ long: "%A %d %B %Y %H:%M"
22
+ verb: "%d %B %Y"
23
+ am: 'am'
24
+ pm: 'pm'
@@ -8,6 +8,7 @@ en:
8
8
  truncate: "…"
9
9
  admin:
10
10
  misc:
11
+ filter_date_format: "mm/dd/yy" # a combination of 'dd', 'mm' and 'yy' with any delimiter. No other interpolation will be done!
11
12
  search: "Search"
12
13
  filter: "Filter"
13
14
  refresh: "Refresh"
@@ -5,7 +5,13 @@ module RailsAdmin
5
5
  module Adapters
6
6
  module ActiveRecord
7
7
  DISABLED_COLUMN_TYPES = [:tsvector, :blob, :binary, :spatial]
8
- LIKE_OPERATOR = ::ActiveRecord::Base.configurations[Rails.env]['adapter'] == "postgresql" ? 'ILIKE' : 'LIKE'
8
+ AR_ADAPTER = ::ActiveRecord::Base.configurations[Rails.env]['adapter']
9
+ LIKE_OPERATOR = AR_ADAPTER == "postgresql" ? 'ILIKE' : 'LIKE'
10
+ BEGINNING_OF_DAY = if AR_ADAPTER == "postgresql"
11
+ lambda { |date| date.beginning_of_day }
12
+ else
13
+ lambda { |date| date.yesterday.end_of_day }
14
+ end
9
15
 
10
16
  def new(params = {})
11
17
  AbstractObject.new(model.new(params))
@@ -46,6 +52,10 @@ module RailsAdmin
46
52
  def destroy(objects)
47
53
  Array.wrap(objects).each &:destroy
48
54
  end
55
+
56
+ def primary_key
57
+ model.primary_key
58
+ end
49
59
 
50
60
  def associations
51
61
  model.reflect_on_all_associations.map do |association|
@@ -53,10 +63,9 @@ module RailsAdmin
53
63
  :name => association.name.to_sym,
54
64
  :pretty_name => association.name.to_s.tr('_', ' ').capitalize,
55
65
  :type => association.macro,
56
- :parent_model_proc => Proc.new { association_parent_model_lookup(association) },
57
- :parent_key => association_parent_key_lookup(association),
58
- :child_model_proc => Proc.new { association_child_model_lookup(association) },
59
- :child_key => association_child_key_lookup(association),
66
+ :model_proc => Proc.new { association_model_lookup(association) },
67
+ :primary_key_proc => Proc.new { association_primary_key_lookup(association) },
68
+ :foreign_key => association_foreign_key_lookup(association),
60
69
  :foreign_type => association_foreign_type_lookup(association),
61
70
  :as => association_as_lookup(association),
62
71
  :polymorphic => association_polymorphic_lookup(association),
@@ -162,27 +171,35 @@ module RailsAdmin
162
171
  end
163
172
  ["(#{column} #{LIKE_OPERATOR} ?)", value]
164
173
  when :datetime, :timestamp, :date
165
- return unless operator != 'default'
166
- values = case operator
174
+ date_format = I18n.t("admin.misc.filter_date_format", :default => I18n.t("admin.misc.filter_date_format", :locale => :en)).gsub('dd', '%d').gsub('mm', '%m').gsub('yy', '%Y')
175
+ case operator
176
+ when 'between'
177
+ start_date = value[1].present? ? (Date.strptime(value[1], date_format).instance_eval(&BEGINNING_OF_DAY) rescue false) : false
178
+ end_date = value[2].present? ? (Date.strptime(value[2], date_format).end_of_day rescue false) : false
167
179
  when 'today'
168
- [Date.today.beginning_of_day, Date.today.end_of_day]
180
+ start_date = Date.today.instance_eval(&BEGINNING_OF_DAY)
181
+ end_date = Date.today.end_of_day
169
182
  when 'yesterday'
170
- [Date.yesterday.beginning_of_day, Date.yesterday.end_of_day]
183
+ start_date = Date.yesterday.instance_eval(&BEGINNING_OF_DAY)
184
+ end_date = Date.yesterday.end_of_day
171
185
  when 'this_week'
172
- [Date.today.beginning_of_week.beginning_of_day, Date.today.end_of_week.end_of_day]
186
+ start_date = Date.today.beginning_of_week.instance_eval(&BEGINNING_OF_DAY)
187
+ end_date = Date.today.end_of_week.end_of_day
173
188
  when 'last_week'
174
- [1.week.ago.to_date.beginning_of_week.beginning_of_day, 1.week.ago.to_date.end_of_week.end_of_day]
175
- when 'less_than'
176
- return if value.blank?
177
- [value.to_i.days.ago, DateTime.now]
178
- when 'more_than'
179
- return if value.blank?
180
- [2000.years.ago, value.to_i.days.ago]
181
- when 'mmddyyyy'
182
- return if (value.blank? || value.match(/([0-9]{8})/).nil?)
183
- [Date.strptime(value.match(/([0-9]{8})/)[1], '%m%d%Y').beginning_of_day, Date.strptime(value.match(/([0-9]{8})/)[1], '%m%d%Y').end_of_day]
189
+ start_date = 1.week.ago.to_date.beginning_of_week.instance_eval(&BEGINNING_OF_DAY)
190
+ end_date = 1.week.ago.to_date.end_of_week.end_of_day
191
+ else # default
192
+ start_date = (Date.strptime(Array.wrap(value).first, date_format).instance_eval(&BEGINNING_OF_DAY) rescue false)
193
+ end_date = (Date.strptime(Array.wrap(value).first, date_format).end_of_day rescue false)
194
+ end
195
+
196
+ if start_date && end_date
197
+ ["(#{column} BETWEEN ? AND ?)", start_date, end_date]
198
+ elsif start_date
199
+ ["(#{column} >= ?)", start_date]
200
+ elsif end_date
201
+ ["(#{column} <= ?)", end_date]
184
202
  end
185
- ["(#{column} BETWEEN ? AND ?)", *values]
186
203
  when :enum
187
204
  return if value.blank?
188
205
  ["(#{column} IN (?))", Array.wrap(value)]
@@ -202,18 +219,11 @@ module RailsAdmin
202
219
  @@polymorphic_parents[name.to_sym]
203
220
  end
204
221
 
205
- def association_parent_model_lookup(association)
206
- case association.macro
207
- when :belongs_to
208
- if association.options[:polymorphic]
209
- RailsAdmin::Adapters::ActiveRecord.polymorphic_parents(association.name) || []
210
- else
211
- association.klass
212
- end
213
- when :has_one, :has_many, :has_and_belongs_to_many
214
- association.active_record
222
+ def association_model_lookup(association)
223
+ if association.options[:polymorphic]
224
+ RailsAdmin::Adapters::ActiveRecord.polymorphic_parents(association.name) || []
215
225
  else
216
- raise "Unknown association type: #{association.macro.inspect}"
226
+ association.klass
217
227
  end
218
228
  end
219
229
 
@@ -235,8 +245,8 @@ module RailsAdmin
235
245
  association.options[:polymorphic]
236
246
  end
237
247
 
238
- def association_parent_key_lookup(association)
239
- [:id]
248
+ def association_primary_key_lookup(association)
249
+ association.options[:primary_key] || association.klass.primary_key
240
250
  end
241
251
 
242
252
  def association_inverse_of_lookup(association)
@@ -247,18 +257,7 @@ module RailsAdmin
247
257
  association.options[:readonly]
248
258
  end
249
259
 
250
- def association_child_model_lookup(association)
251
- case association.macro
252
- when :belongs_to
253
- association.active_record
254
- when :has_one, :has_many, :has_and_belongs_to_many
255
- association.klass
256
- else
257
- raise "Unknown association type: #{association.macro.inspect}"
258
- end
259
- end
260
-
261
- def association_child_key_lookup(association)
260
+ def association_foreign_key_lookup(association)
262
261
  association.foreign_key.to_sym
263
262
  end
264
263
  end
@@ -25,12 +25,16 @@ module RailsAdmin
25
25
  elsif request.put? # UPDATE
26
26
 
27
27
  @cached_assocations_hash = associations_hash
28
- @attributes = get_attributes
29
28
  @modified_assoc = []
30
29
 
31
30
  @old_object = @object.dup
32
- @model_config.update.fields.map { |f| f.parse_input(@attributes) if f.respond_to?(:parse_input) }
33
- @object.set_attributes(@attributes, _attr_accessible_role)
31
+
32
+ sanitize_params_for! :update
33
+
34
+ @object.set_attributes(params[@abstract_model.param_key], _attr_accessible_role)
35
+ @authorization_adapter && @authorization_adapter.attributes_for(:update, @abstract_model).each do |name, value|
36
+ @object.send("#{name}=", value)
37
+ end
34
38
 
35
39
  if @object.save
36
40
  @auditing_adapter && @auditing_adapter.update_object(@abstract_model, @object, @cached_assocations_hash, associations_hash, @modified_assoc, @old_object, _current_user)
@@ -37,7 +37,9 @@ module RailsAdmin
37
37
 
38
38
  format.json do
39
39
  output = if params[:compact]
40
- @objects.map{ |o| { :id => o.id, :label => o.send(@model_config.object_label_method) } }
40
+ primary_key_method = @association ? @association.associated_primary_key : @model_config.abstract_model.primary_key
41
+ label_method = @model_config.object_label_method
42
+ @objects.map{ |o| { :id => o.send(primary_key_method), :label => o.send(label_method) } }
41
43
  else
42
44
  @objects.to_json(@schema)
43
45
  end
@@ -34,13 +34,13 @@ module RailsAdmin
34
34
 
35
35
  @modified_assoc = []
36
36
  @object = @abstract_model.new
37
- @attributes = get_attributes
38
- @model_config.create.fields.each {|f| f.parse_input(@attributes) if f.respond_to?(:parse_input) }
37
+ sanitize_params_for! :create
38
+
39
+ @object.set_attributes(params[@abstract_model.param_key], _attr_accessible_role)
39
40
  @authorization_adapter && @authorization_adapter.attributes_for(:create, @abstract_model).each do |name, value|
40
41
  @object.send("#{name}=", value)
41
42
  end
42
- @object.set_attributes(@attributes, _attr_accessible_role)
43
-
43
+
44
44
  if @object.save
45
45
  @auditing_adapter && @auditing_adapter.create_object("Created #{@model_config.with(:object => @object).object_label}", @object, @abstract_model, _current_user)
46
46
  respond_to do |format|
@@ -28,7 +28,7 @@ module RailsAdmin
28
28
 
29
29
  def find custom_key, bindings = {}
30
30
  init_actions!
31
- action = @@actions.find{ |a| a.custom_key == custom_key }.with(bindings)
31
+ action = @@actions.find{ |a| a.custom_key == custom_key }.try(:with, bindings)
32
32
  bindings[:controller] ? (action.try(:visible?) && action || nil) : action
33
33
  end
34
34