obitum-rails_admin 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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