active_scaffold 3.2.12 → 3.2.13
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +14 -1
- data/app/assets/javascripts/jquery/active_scaffold.js +8 -6
- data/app/assets/javascripts/prototype/active_scaffold.js +4 -3
- data/config/locales/de.yml +1 -1
- data/config/locales/en.yml +1 -1
- data/config/locales/es.yml +1 -1
- data/config/locales/fr.yml +1 -1
- data/config/locales/hu.yml +1 -1
- data/config/locales/ja.yml +1 -1
- data/config/locales/ru.yml +6 -4
- data/frontends/default/views/_base_form.html.erb +1 -1
- data/frontends/default/views/_form_hidden_attribute.html.erb +6 -1
- data/frontends/default/views/_horizontal_subform_header.html.erb +1 -1
- data/frontends/default/views/_horizontal_subform_record.html.erb +1 -1
- data/frontends/default/views/_list_inline_adapter.html.erb +1 -1
- data/frontends/default/views/_render_field.js.erb +1 -1
- data/frontends/default/views/_show.html.erb +1 -1
- data/frontends/default/views/_update_actions.html.erb +1 -1
- data/frontends/default/views/_vertical_subform_record.html.erb +1 -1
- data/lib/active_scaffold.rb +3 -3
- data/lib/active_scaffold/actions/core.rb +5 -11
- data/lib/active_scaffold/actions/delete.rb +0 -1
- data/lib/active_scaffold/actions/mark.rb +9 -4
- data/lib/active_scaffold/bridges/date_picker.rb +1 -1
- data/lib/active_scaffold/bridges/date_picker/ext.rb +7 -0
- data/lib/active_scaffold/bridges/date_picker/helper.rb +1 -1
- data/lib/active_scaffold/bridges/shared/date_bridge.rb +3 -3
- data/lib/active_scaffold/config/nested.rb +1 -1
- data/lib/active_scaffold/config/show.rb +1 -1
- data/lib/active_scaffold/config/update.rb +1 -1
- data/lib/active_scaffold/data_structures/action_link.rb +6 -0
- data/lib/active_scaffold/data_structures/action_links.rb +7 -2
- data/lib/active_scaffold/data_structures/column.rb +8 -8
- data/lib/active_scaffold/data_structures/nested_info.rb +5 -1
- data/lib/active_scaffold/extensions/action_controller_rendering.rb +0 -2
- data/lib/active_scaffold/extensions/action_controller_rescueing.rb +7 -0
- data/lib/active_scaffold/finder.rb +58 -40
- data/lib/active_scaffold/helpers/form_column_helpers.rb +4 -1
- data/lib/active_scaffold/helpers/search_column_helpers.rb +4 -2
- data/lib/active_scaffold/helpers/view_helpers.rb +4 -1
- data/lib/active_scaffold/tableless.rb +0 -1
- data/lib/active_scaffold/version.rb +1 -1
- data/lib/generators/active_scaffold/active_scaffold_generator.rb +1 -0
- metadata +10 -9
data/CHANGELOG
CHANGED
@@ -1,4 +1,17 @@
|
|
1
|
-
= 3.2.
|
1
|
+
= 3.2.13 (not released yet)
|
2
|
+
- Fix destroy action, was broken in 3.2.12
|
3
|
+
- Remove default :method sorting for associations, it wasn't useful and can be slow
|
4
|
+
- Rescue from ActiveScaffold::ActionNotAllowed and ActiveScaffold::RecordNotAllowed with 401 response, it can be overrided with deny_access method in ApplicationController.
|
5
|
+
- Allow to set arrays in search_sql so one column can search in multiple db columns, resulting sql chunks will be OR'ed
|
6
|
+
- Hide text input on searching for null or not null
|
7
|
+
- Add some classes to forms to improve CSS customization
|
8
|
+
- Fix nested links for STI controllers with common configuration in a base controller
|
9
|
+
- Fix adding routes twice in active_scaffold generator
|
10
|
+
- Restore old behavior for action_link's security_method, ignore_method already hides the link
|
11
|
+
- Add data-cancel-refresh to action links, so nested scaffold's behaviour can be applied to other action links and when adapter is closed row will be refreshed.
|
12
|
+
- fix support for tableless models in rails >= 3.2.5
|
13
|
+
|
14
|
+
= 3.2.12
|
2
15
|
- improve support for tableless models, add support for count
|
3
16
|
- fix div id for nested scaffolds
|
4
17
|
- add config.timestamped_messages and config.highlight_messages
|
@@ -72,8 +72,8 @@ jQuery(document).ready(function() {
|
|
72
72
|
|
73
73
|
if (action_link) {
|
74
74
|
var cancel_url = as_cancel.attr('href');
|
75
|
-
var refresh_data =
|
76
|
-
if (refresh_data
|
75
|
+
var refresh_data = action_link.tag.data('cancel-refresh');
|
76
|
+
if (!refresh_data || !cancel_url) {
|
77
77
|
action_link.close();
|
78
78
|
return false;
|
79
79
|
}
|
@@ -166,11 +166,13 @@ jQuery(document).ready(function() {
|
|
166
166
|
});
|
167
167
|
|
168
168
|
jQuery('select.as_search_range_option').live('change', function(event) {
|
169
|
-
|
169
|
+
var element = jQuery(this);
|
170
|
+
ActiveScaffold[element.val() == 'BETWEEN' ? 'show' : 'hide'](element.closest('dd').find('.as_search_range_between'));
|
171
|
+
ActiveScaffold[(element.val() == 'null' || element.val() == 'not_null') ? 'hide' : 'show'](element.attr('id').replace(/_opt/, '_numeric'));
|
170
172
|
return true;
|
171
173
|
});
|
172
174
|
|
173
|
-
jQuery('select.
|
175
|
+
jQuery('select.as_search_date_time_option').live('change', function(event) {
|
174
176
|
var element = jQuery(this);
|
175
177
|
ActiveScaffold[!(element.val() == 'PAST' || element.val() == 'FUTURE' || element.val() == 'RANGE') ? 'show' : 'hide'](element.attr('id').replace(/_opt/, '_numeric'));
|
176
178
|
ActiveScaffold[(element.val() == 'PAST' || element.val() == 'FUTURE') ? 'show' : 'hide'](element.attr('id').replace(/_opt/, '_trend'));
|
@@ -440,7 +442,7 @@ var ActiveScaffold = {
|
|
440
442
|
update_inplace_edit: function(element, value, empty) {
|
441
443
|
if (typeof(element) == 'string') element = '#' + element;
|
442
444
|
this.replace_html(jQuery(element), value);
|
443
|
-
|
445
|
+
jQuery(element).closest('td')[empty ? 'addClass' : 'removeClass']('empty');
|
444
446
|
},
|
445
447
|
|
446
448
|
hide: function(element) {
|
@@ -971,7 +973,7 @@ ActiveScaffold.ActionLink.Abstract = Class.extend({
|
|
971
973
|
this.adapter = element;
|
972
974
|
this.adapter.addClass('as_adapter');
|
973
975
|
this.adapter.data('action_link', this);
|
974
|
-
if (this.refresh_url) jQuery('.as_cancel
|
976
|
+
if (this.refresh_url) jQuery('.as_cancel', this.adapter).attr('href', this.refresh_url);
|
975
977
|
}
|
976
978
|
});
|
977
979
|
|
@@ -95,10 +95,10 @@ document.observe("dom:loaded", function() {
|
|
95
95
|
var action_link = ActiveScaffold.find_action_link(as_cancel);
|
96
96
|
|
97
97
|
if (action_link) {
|
98
|
-
var refresh_data =
|
99
|
-
if (refresh_data
|
98
|
+
var refresh_data = action_link.readAttribute('data-cancel-refresh');
|
99
|
+
if (refresh_data && action_link.refresh_url) {
|
100
100
|
event.memo.url = action_link.refresh_url;
|
101
|
-
} else if (refresh_data
|
101
|
+
} else if (!refresh_data || as_cancel.readAttribute('href').blank()) {
|
102
102
|
action_link.close();
|
103
103
|
event.stop();
|
104
104
|
}
|
@@ -252,6 +252,7 @@ document.observe("dom:loaded", function() {
|
|
252
252
|
document.on('change', 'select.as_search_range_option', function(event) {
|
253
253
|
var element = event.findElement();
|
254
254
|
Element[element.value == 'BETWEEN' ? 'show' : 'hide'](element.readAttribute('id').sub('_opt', '_between'));
|
255
|
+
Element[(element.value == 'null' || element.value == 'not_null') ? 'hide' : 'show'](element.readAttribute('id').sub('_opt', '_numeric'));
|
255
256
|
return true;
|
256
257
|
});
|
257
258
|
document.on('change', 'select.as_search_date_time_option', function(event) {
|
data/config/locales/de.yml
CHANGED
data/config/locales/en.yml
CHANGED
data/config/locales/es.yml
CHANGED
data/config/locales/fr.yml
CHANGED
data/config/locales/hu.yml
CHANGED
data/config/locales/ja.yml
CHANGED
data/config/locales/ru.yml
CHANGED
@@ -38,7 +38,7 @@ ru:
|
|
38
38
|
inplace_edit_handle: '--'
|
39
39
|
live_search: 'Поиск'
|
40
40
|
loading: 'Загрузка…'
|
41
|
-
mark_all_records: "
|
41
|
+
mark_all_records: "Отметить все"
|
42
42
|
next: 'Следующее'
|
43
43
|
no_entries: 'Нет записей'
|
44
44
|
no_options: 'Нет вариантов'
|
@@ -48,8 +48,10 @@ ru:
|
|
48
48
|
previous: 'Предыдущее'
|
49
49
|
print: 'Печать'
|
50
50
|
records_marked:
|
51
|
-
one: "1
|
52
|
-
|
51
|
+
one: "Отмечена 1 запись"
|
52
|
+
few: "Отмечено %{count} записи"
|
53
|
+
many: "Отмечено %{count} записей"
|
54
|
+
other: "Отмечено %{count} записи"
|
53
55
|
refresh: 'Обновить'
|
54
56
|
remove: 'Удалить'
|
55
57
|
remove_file: 'Удалить или заменить файл'
|
@@ -100,7 +102,7 @@ ru:
|
|
100
102
|
months: 'месяцев'
|
101
103
|
years: 'лет'
|
102
104
|
optional_attributes: 'Дополнительные настройки'
|
103
|
-
null: 'Пусто'
|
105
|
+
:null: 'Пусто'
|
104
106
|
not_null: 'Не пусто'
|
105
107
|
date_picker_options:
|
106
108
|
weekHeader: 'Нед.'
|
@@ -20,7 +20,7 @@ options = {:onsubmit => onsubmit,
|
|
20
20
|
:class => "as_form #{form_action.to_s}",
|
21
21
|
:method => method,
|
22
22
|
'data-loading' => true}
|
23
|
-
cancel_options = {:class => 'as_cancel'
|
23
|
+
cancel_options = {:class => 'as_cancel'}
|
24
24
|
|
25
25
|
cancel_options[:remote] = true if xhr #cancel link does nt have to care about multipart forms
|
26
26
|
if xhr && multipart # file_uploads
|
@@ -5,7 +5,7 @@
|
|
5
5
|
hidden = column_renders_as(column) == :hidden
|
6
6
|
next unless in_subform?(column, parent_record)
|
7
7
|
-%>
|
8
|
-
<th class="<%= "#{'required' if column.required?} #{'hidden' if hidden}" %>"><label><%= column.label unless hidden %></label></th>
|
8
|
+
<th class="<%= "#{column.name}-column #{'required' if column.required?} #{'hidden' if hidden}" %>"><label><%= column.label unless hidden %></label></th>
|
9
9
|
<% end -%>
|
10
10
|
</tr>
|
11
11
|
</thead>
|
@@ -24,7 +24,7 @@
|
|
24
24
|
<% unless readonly and not @record.new_record? or not @record.authorized_for?(:crud_type => crud_type, :column => column.name) -%>
|
25
25
|
<%= render :partial => form_partial_for_column(column), :locals => { :column => column, :scope => scope } -%>
|
26
26
|
<% else -%>
|
27
|
-
|
27
|
+
<%= content_tag :span, get_column_value(@record, column), active_scaffold_input_options(column, scope).except(:name) -%>
|
28
28
|
<% end -%>
|
29
29
|
</td>
|
30
30
|
<% end -%>
|
@@ -12,7 +12,7 @@
|
|
12
12
|
<tr class="inline-adapter" id="<%= element_row_id :action => :nested %>">
|
13
13
|
<td colspan="<%= column_count %>" class="inline-adapter-cell">
|
14
14
|
<div class="<%= "#{params[:action]}-view" if params[:action] %> <%= "#{nested? ? nested.name : id_from_controller(params[:controller])}-view" %> view">
|
15
|
-
<%= link_to(as_(:close), '', :class => 'inline-adapter-close as_cancel', :remote => true, :title => as_(:close)
|
15
|
+
<%= link_to(as_(:close), '', :class => 'inline-adapter-close as_cancel', :remote => true, :title => as_(:close)) -%>
|
16
16
|
<%= payload -%>
|
17
17
|
</div>
|
18
18
|
</td>
|
@@ -2,7 +2,7 @@
|
|
2
2
|
column = if render_field.is_a? ActiveScaffold::DataStructures::Column
|
3
3
|
render_field
|
4
4
|
else
|
5
|
-
active_scaffold_config.columns[render_field.to_sym]
|
5
|
+
active_scaffold_config.columns[render_field.to_sym]
|
6
6
|
end
|
7
7
|
@rendered ||= Set.new
|
8
8
|
return if @rendered.include? column.name
|
@@ -3,6 +3,6 @@
|
|
3
3
|
<%= render :partial => 'show_columns', :locals => {:columns => active_scaffold_config.show.columns} -%>
|
4
4
|
|
5
5
|
<p class="form-footer">
|
6
|
-
<%= link_to as_(:close), main_path_to_return, :class => 'as_cancel', :remote => request.xhr
|
6
|
+
<%= link_to as_(:close), main_path_to_return, :class => 'as_cancel', :remote => request.xhr? %>
|
7
7
|
<%= loading_indicator_tag(:action => :create, :id => params[:id]) %>
|
8
8
|
</p>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<div class="active-scaffold-header">
|
2
2
|
<div class="actions">
|
3
3
|
<% active_scaffold_config.action_links.member.each do |link| -%>
|
4
|
-
<% next unless link.action == '
|
4
|
+
<% next unless link.action == 'index' -%>
|
5
5
|
<% next if skip_action_link(link) -%>
|
6
6
|
<%= record.authorized_for?(:crud_type => link.crud_type, :action => link.action) ? render_action_link(link, url_options, record) : "<a class='disabled'>#{link.label}</a>" -%>
|
7
7
|
<% end -%>
|
@@ -24,7 +24,7 @@
|
|
24
24
|
<% unless readonly and not @record.new_record? or not @record.authorized_for?(:crud_type => crud_type, :column => column.name) -%>
|
25
25
|
<%= render :partial => form_partial_for_column(column), :locals => { :column => column, :scope => scope } -%>
|
26
26
|
<% else -%>
|
27
|
-
|
27
|
+
<%= content_tag :span, get_column_value(@record, column), active_scaffold_input_options(column, scope).except(:name) -%>
|
28
28
|
<% end -%>
|
29
29
|
</li>
|
30
30
|
<% end -%>
|
data/lib/active_scaffold.rb
CHANGED
@@ -266,11 +266,11 @@ module ActiveScaffold
|
|
266
266
|
unless controller.nil?
|
267
267
|
options.reverse_merge! :label => column.label, :position => :after, :type => :member, :controller => (controller == :polymorph ? controller : controller.controller_path), :column => column
|
268
268
|
options[:parameters] ||= {}
|
269
|
-
options[:parameters].reverse_merge! :
|
269
|
+
options[:parameters].reverse_merge! :association => column.association.name
|
270
270
|
if column.plural_association?
|
271
271
|
# note: we can't create nested scaffolds on :through associations because there's no reverse association.
|
272
272
|
|
273
|
-
ActiveScaffold::DataStructures::ActionLink.new('index', options) #unless column.through_association?
|
273
|
+
ActiveScaffold::DataStructures::ActionLink.new('index', options.merge(:refresh_on_close => true)) #unless column.through_association?
|
274
274
|
else
|
275
275
|
actions = controller.active_scaffold_config.actions unless controller == :polymorph
|
276
276
|
actions ||= [:create, :update, :show]
|
@@ -285,7 +285,7 @@ module ActiveScaffold
|
|
285
285
|
def link_for_association_as_scope(scope, options = {})
|
286
286
|
options.reverse_merge! :label => scope, :position => :after, :type => :member, :controller => controller_path
|
287
287
|
options[:parameters] ||= {}
|
288
|
-
options[:parameters].reverse_merge! :
|
288
|
+
options[:parameters].reverse_merge! :named_scope => scope
|
289
289
|
ActiveScaffold::DataStructures::ActionLink.new('index', options)
|
290
290
|
end
|
291
291
|
|
@@ -4,6 +4,7 @@ module ActiveScaffold::Actions
|
|
4
4
|
base.class_eval do
|
5
5
|
before_filter :register_constraints_with_action_columns, :if => :embedded?
|
6
6
|
after_filter :clear_flashes
|
7
|
+
rescue_from ActiveScaffold::RecordNotAllowed, ActiveScaffold::ActionNotAllowed, :with => :deny_access
|
7
8
|
end
|
8
9
|
base.helper_method :nested?
|
9
10
|
base.helper_method :calculate
|
@@ -75,6 +76,10 @@ module ActiveScaffold::Actions
|
|
75
76
|
end
|
76
77
|
end
|
77
78
|
|
79
|
+
def each_marked_record(&block)
|
80
|
+
active_scaffold_config.model.find(marked_records.to_a).each &block
|
81
|
+
end
|
82
|
+
|
78
83
|
def marked_records
|
79
84
|
active_scaffold_session_storage[:marked_records] ||= Set.new
|
80
85
|
end
|
@@ -193,16 +198,5 @@ module ActiveScaffold::Actions
|
|
193
198
|
(default_formats + active_scaffold_config.formats).uniq
|
194
199
|
end
|
195
200
|
end
|
196
|
-
|
197
|
-
def response_code_for_rescue(exception)
|
198
|
-
case exception
|
199
|
-
when ActiveScaffold::RecordNotAllowed
|
200
|
-
"403 Record Not Allowed"
|
201
|
-
when ActiveScaffold::ActionNotAllowed
|
202
|
-
"403 Action Not Allowed"
|
203
|
-
else
|
204
|
-
super
|
205
|
-
end
|
206
|
-
end
|
207
201
|
end
|
208
202
|
end
|
@@ -49,7 +49,6 @@ module ActiveScaffold::Actions
|
|
49
49
|
@record ||= destroy_find_record
|
50
50
|
begin
|
51
51
|
self.successful = @record.destroy
|
52
|
-
@record.as_marked = false if successful?
|
53
52
|
rescue Exception => ex
|
54
53
|
flash[:warning] = as_(:cant_destroy_record, :record => @record.to_label)
|
55
54
|
self.successful = false
|
@@ -56,9 +56,9 @@ module ActiveScaffold::Actions
|
|
56
56
|
if params[:id]
|
57
57
|
find_if_allowed(params[:id], :read).as_marked = true
|
58
58
|
elsif active_scaffold_config.mark.mark_all_mode == :page && !mark_all_scope_forced?
|
59
|
-
each_record_in_page {|record|
|
59
|
+
each_record_in_page { |record| record.as_marked = true }
|
60
60
|
else
|
61
|
-
each_record_in_scope {|record|
|
61
|
+
each_record_in_scope { |record| record.as_marked = true }
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
@@ -66,12 +66,17 @@ module ActiveScaffold::Actions
|
|
66
66
|
if params[:id]
|
67
67
|
find_if_allowed(params[:id], :read).as_marked = false
|
68
68
|
elsif active_scaffold_config.mark.mark_all_mode == :page
|
69
|
-
each_record_in_page {|record|
|
69
|
+
each_record_in_page { |record| record.as_marked = false }
|
70
70
|
else
|
71
|
-
each_record_in_scope {|record|
|
71
|
+
each_record_in_scope { |record| record.as_marked = false }
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
+
def do_destroy
|
76
|
+
super
|
77
|
+
@record.as_marked = false if successful?
|
78
|
+
end
|
79
|
+
|
75
80
|
# The default security delegates to ActiveRecordPermissions.
|
76
81
|
# You may override the method to customize.
|
77
82
|
def mark_authorized?
|
@@ -8,7 +8,7 @@ module ActiveScaffold::Bridges
|
|
8
8
|
ActiveScaffold.js_framework == :jquery
|
9
9
|
end
|
10
10
|
def self.localization
|
11
|
-
|
11
|
+
"jQuery(function($){
|
12
12
|
if (typeof($.datepicker) === 'object') {
|
13
13
|
#{Helper.date_options_for_locales}
|
14
14
|
$.datepicker.setDefaults($.datepicker.regional['#{::I18n.locale}']);
|
@@ -49,6 +49,13 @@ ActionView::Base.class_eval do
|
|
49
49
|
end
|
50
50
|
ActiveScaffold::Finder::ClassMethods.module_eval do
|
51
51
|
include ActiveScaffold::Bridges::Shared::DateBridge::Finder::ClassMethods
|
52
|
+
def datetime_conversion_for_condition(column)
|
53
|
+
if column.search_ui == :date_picker
|
54
|
+
:to_date
|
55
|
+
else
|
56
|
+
super
|
57
|
+
end
|
58
|
+
end
|
52
59
|
alias_method :condition_for_date_picker_type, :condition_for_date_bridge_type
|
53
60
|
alias_method :condition_for_datetime_picker_type, :condition_for_date_picker_type
|
54
61
|
end
|
@@ -158,7 +158,7 @@ module ActiveScaffold::Bridges
|
|
158
158
|
options = active_scaffold_input_text_options(options.merge(column.options))
|
159
159
|
options[:class] << " #{column.search_ui.to_s}"
|
160
160
|
options[:style] = (options[:show].nil? || options[:show]) ? nil : "display: none"
|
161
|
-
format = options.delete(:format) || column.
|
161
|
+
format = options.delete(:format) || column.search_ui == :date_picker ? :default : :picker
|
162
162
|
datepicker_format_options(column, format, options)
|
163
163
|
text_field_tag("#{options[:name]}[#{name}]", value ? l(value, :format => format) : nil, options.merge(:id => "#{options[:id]}_#{name}", :name => "#{options[:name]}[#{name}]"))
|
164
164
|
end
|
@@ -112,15 +112,15 @@ module ActiveScaffold
|
|
112
112
|
column.search_sql.call(from_value, to_value, operator)
|
113
113
|
else
|
114
114
|
unless operator.nil?
|
115
|
-
["
|
115
|
+
["%{search_sql} #{value[:opt]} ?", from_value.to_s(:db)] unless from_value.nil?
|
116
116
|
else
|
117
|
-
["
|
117
|
+
["%{search_sql} BETWEEN ? AND ?", from_value.to_s(:db), to_value.to_s(:db)] unless from_value.nil? && to_value.nil?
|
118
118
|
end
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
122
|
def date_bridge_from_to(column, value)
|
123
|
-
conversion = column
|
123
|
+
conversion = datetime_conversion_for_condition(column)
|
124
124
|
case value[:opt]
|
125
125
|
when 'RANGE'
|
126
126
|
date_bridge_from_to_for_range(column, value).collect(&conversion)
|
@@ -21,7 +21,7 @@ module ActiveScaffold::Config
|
|
21
21
|
def add_link(attribute, options = {})
|
22
22
|
column = @core.columns[attribute.to_sym]
|
23
23
|
unless column.nil? || column.association.nil?
|
24
|
-
options.reverse_merge! :security_method => :nested_authorized?, :label => column.association.klass.model_name.human({:count => 2, :default => column.association.klass.name.pluralize})
|
24
|
+
options.reverse_merge! :security_method => :nested_authorized?, :label => column.association.klass.model_name.human({:count => 2, :default => column.association.klass.name.pluralize})
|
25
25
|
action_link = @core.link_for_association(column, options)
|
26
26
|
action_link.action ||= :index
|
27
27
|
@core.action_links.add_to_group(action_link, action_group) unless action_link.nil?
|
@@ -11,7 +11,7 @@ module ActiveScaffold::Config
|
|
11
11
|
# global level configuration
|
12
12
|
# --------------------------
|
13
13
|
cattr_accessor :link
|
14
|
-
@@link = ActiveScaffold::DataStructures::ActionLink.new('show', :label => :show, :type => :member, :security_method => :show_authorized?)
|
14
|
+
@@link = ActiveScaffold::DataStructures::ActionLink.new('show', :label => :show, :type => :member, :security_method => :show_authorized?, :ignore_method => :show_ignore?)
|
15
15
|
# instance-level configuration
|
16
16
|
# ----------------------------
|
17
17
|
|
@@ -15,7 +15,7 @@ module ActiveScaffold::Config
|
|
15
15
|
def self.link=(val)
|
16
16
|
@@link = val
|
17
17
|
end
|
18
|
-
@@link = ActiveScaffold::DataStructures::ActionLink.new('edit', :label => :edit, :type => :member, :security_method => :update_authorized?)
|
18
|
+
@@link = ActiveScaffold::DataStructures::ActionLink.new('edit', :label => :edit, :type => :member, :security_method => :update_authorized?, :ignore_method => :update_ignore?)
|
19
19
|
|
20
20
|
# instance-level configuration
|
21
21
|
# ----------------------------
|
@@ -82,6 +82,7 @@ module ActiveScaffold::DataStructures
|
|
82
82
|
end
|
83
83
|
|
84
84
|
# what method to call on the controller to see if this action_link should be visible
|
85
|
+
# if method return false, link will be disabled
|
85
86
|
# note that this is only the UI part of the security. to prevent URL hax0rz, you also need security on requests (e.g. don't execute update method unless authorized).
|
86
87
|
attr_writer :security_method
|
87
88
|
def security_method
|
@@ -91,7 +92,12 @@ module ActiveScaffold::DataStructures
|
|
91
92
|
def security_method_set?
|
92
93
|
!!@security_method
|
93
94
|
end
|
95
|
+
|
96
|
+
# enable it to refresh the parent row when the view is closed
|
97
|
+
attr_accessor :refresh_on_close
|
94
98
|
|
99
|
+
# what method to call on the controller to see if this action_link should be visible
|
100
|
+
# if method return true, link won't be displayed
|
95
101
|
attr_accessor :ignore_method
|
96
102
|
|
97
103
|
# the crud type of the (eventual?) action. different than :method, because this crud action may not be imminent.
|
@@ -121,7 +121,12 @@ module ActiveScaffold::DataStructures
|
|
121
121
|
first_action = false
|
122
122
|
end
|
123
123
|
elsif controller.nil? || !skip_action_link(controller, link, *(Array(options[:for])))
|
124
|
-
|
124
|
+
security_method = link.security_method_set? || controller.respond_to?(link.security_method)
|
125
|
+
authorized = if security_method
|
126
|
+
controller.send(link.security_method, *args)
|
127
|
+
else
|
128
|
+
options[:for].nil? ? true : options[:for].authorized_for?(:crud_type => link.crud_type, :action => link.action)
|
129
|
+
end
|
125
130
|
yield(self, link, {:authorized => authorized, :first_action => first_action, :level => options[:level]})
|
126
131
|
first_action = false
|
127
132
|
end
|
@@ -173,7 +178,7 @@ module ActiveScaffold::DataStructures
|
|
173
178
|
protected
|
174
179
|
|
175
180
|
def skip_action_link(controller, link, *args)
|
176
|
-
|
181
|
+
!link.ignore_method.nil? && controller.respond_to?(link.ignore_method) && controller.send(link.ignore_method, *args)
|
177
182
|
end
|
178
183
|
|
179
184
|
# called during clone or dup. makes the clone/dup deeper.
|
@@ -179,7 +179,10 @@ module ActiveScaffold::DataStructures
|
|
179
179
|
# describes how to search on a column
|
180
180
|
# search = true default, uses intelligent search sql
|
181
181
|
# search = "CONCAT(a, b)" define your own sql for searching. this should be the "left-side" of a WHERE condition. the operator and value will be supplied by ActiveScaffold.
|
182
|
-
|
182
|
+
# search = [:a, :b] searches in both fields
|
183
|
+
def search_sql=(value)
|
184
|
+
@search_sql = (value == true || value.is_a?(Proc)) ? value : Array(value)
|
185
|
+
end
|
183
186
|
def search_sql
|
184
187
|
self.initialize_search_sql if @search_sql === true
|
185
188
|
@search_sql
|
@@ -281,6 +284,7 @@ module ActiveScaffold::DataStructures
|
|
281
284
|
# instantiation is handled internally through the DataStructures::Columns object
|
282
285
|
def initialize(name, active_record_class) #:nodoc:
|
283
286
|
self.name = name.to_sym
|
287
|
+
@tableless = active_record_class < ActiveScaffold::Tableless
|
284
288
|
@column = active_record_class.columns_hash[self.name.to_s]
|
285
289
|
@association = active_record_class.reflect_on_association(self.name)
|
286
290
|
@autolink = !@association.nil?
|
@@ -352,11 +356,7 @@ module ActiveScaffold::DataStructures
|
|
352
356
|
# we don't automatically enable method sorting for virtual columns because it's slow, and we expect fewer complaints this way.
|
353
357
|
self.sort = false
|
354
358
|
else
|
355
|
-
if
|
356
|
-
self.sort = {:method => "#{self.name}.to_s"}
|
357
|
-
elsif self.plural_association?
|
358
|
-
self.sort = {:method => "#{self.name}.join(',')"}
|
359
|
-
elsif @active_record_class.connection
|
359
|
+
if column && @tableless
|
360
360
|
self.sort = {:sql => self.field}
|
361
361
|
else
|
362
362
|
self.sort = false
|
@@ -367,9 +367,9 @@ module ActiveScaffold::DataStructures
|
|
367
367
|
def initialize_search_sql
|
368
368
|
self.search_sql = unless self.virtual?
|
369
369
|
if association.nil?
|
370
|
-
self.field.to_s unless @
|
370
|
+
self.field.to_s unless @tableless
|
371
371
|
elsif !self.polymorphic_association?
|
372
|
-
[association.klass.quoted_table_name, association.klass.quoted_primary_key].join('.') unless association.klass
|
372
|
+
[association.klass.quoted_table_name, association.klass.quoted_primary_key].join('.') unless association.klass < ActiveScaffold::Tableless
|
373
373
|
end
|
374
374
|
end
|
375
375
|
end
|
@@ -6,7 +6,11 @@ module ActiveScaffold::DataStructures
|
|
6
6
|
nested_info[:name] = (params[:association] || params[:named_scope]).to_sym
|
7
7
|
nested_info[:parent_scaffold] = "#{params[:parent_scaffold].to_s.camelize}Controller".constantize
|
8
8
|
nested_info[:parent_model] = nested_info[:parent_scaffold].active_scaffold_config.model
|
9
|
-
nested_info[:parent_id] = params[
|
9
|
+
nested_info[:parent_id] = if params[:association].nil?
|
10
|
+
params[nested_info[:parent_model].name.foreign_key]
|
11
|
+
else
|
12
|
+
params[nested_info[:parent_model].reflect_on_association(params[:association].to_sym).active_record.name.foreign_key]
|
13
|
+
end
|
10
14
|
if nested_info[:parent_id]
|
11
15
|
unless params[:association].nil?
|
12
16
|
ActiveScaffold::DataStructures::NestedInfoAssociation.new(model, nested_info)
|
@@ -17,13 +17,18 @@ module ActiveScaffold
|
|
17
17
|
|
18
18
|
where_clauses = []
|
19
19
|
columns.each do |column|
|
20
|
-
|
20
|
+
Array(column.search_sql).each do |search_sql|
|
21
|
+
where_clauses << "#{search_sql} #{(column.column.nil? || column.column.text?) ? ActiveScaffold::Finder.like_operator : '='} ?"
|
22
|
+
end
|
21
23
|
end
|
22
24
|
phrase = where_clauses.join(' OR ')
|
23
25
|
|
24
26
|
tokens.collect do |value|
|
25
27
|
columns.inject([phrase]) do |condition, column|
|
26
|
-
|
28
|
+
Array(column.search_sql).size.times do
|
29
|
+
condition.push((column.column.nil? || column.column.text?) ? like_pattern.sub('?', value) : column.column.type_cast(value))
|
30
|
+
end
|
31
|
+
condition
|
27
32
|
end
|
28
33
|
end
|
29
34
|
end
|
@@ -39,32 +44,37 @@ module ActiveScaffold
|
|
39
44
|
return unless column and column.search_sql and not value.blank?
|
40
45
|
search_ui = column.search_ui || column.column.try(:type)
|
41
46
|
begin
|
42
|
-
if search_ui && self.respond_to?("condition_for_#{search_ui}_type")
|
47
|
+
sql, *values = if search_ui && self.respond_to?("condition_for_#{search_ui}_type")
|
43
48
|
self.send("condition_for_#{search_ui}_type", column, value, like_pattern)
|
44
49
|
else
|
45
|
-
|
50
|
+
if column.search_sql.instance_of? Proc
|
51
|
+
column.search_sql.call(value)
|
52
|
+
else
|
46
53
|
case search_ui
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
["
|
54
|
+
when :boolean, :checkbox
|
55
|
+
["%{search_sql} = ?", column.column ? column.column.type_cast(value) : value]
|
56
|
+
when :integer, :decimal, :float
|
57
|
+
condition_for_numeric(column, value)
|
58
|
+
when :string, :range
|
59
|
+
condition_for_range(column, value, like_pattern)
|
60
|
+
when :date, :time, :datetime, :timestamp
|
61
|
+
condition_for_datetime(column, value)
|
62
|
+
when :select, :multi_select, :country, :usa_state
|
63
|
+
["%{search_sql} in (?)", [Array(value)]]
|
64
|
+
else
|
65
|
+
if column.column.nil? || column.column.text?
|
66
|
+
["%{search_sql} #{ActiveScaffold::Finder.like_operator} ?", like_pattern.sub('?', value)]
|
57
67
|
else
|
58
|
-
|
59
|
-
|
60
|
-
else
|
61
|
-
["#{column.search_sql} = ?", column.column.type_cast(value)]
|
62
|
-
end
|
68
|
+
["%{search_sql} = ?", column.column.type_cast(value)]
|
69
|
+
end
|
63
70
|
end
|
64
|
-
else
|
65
|
-
column.search_sql.call(value)
|
66
71
|
end
|
67
72
|
end
|
73
|
+
return nil unless sql
|
74
|
+
|
75
|
+
conditions = [column.search_sql.collect { |search_sql| sql % {:search_sql => search_sql} }.join(' OR ')]
|
76
|
+
conditions += values*column.search_sql.size if values.present?
|
77
|
+
conditions
|
68
78
|
rescue Exception => e
|
69
79
|
logger.error Time.now.to_s + "#{e.inspect} -- on the ActiveScaffold column :#{column.name}, search_ui = #{search_ui} in #{self.name}"
|
70
80
|
raise e
|
@@ -73,33 +83,33 @@ module ActiveScaffold
|
|
73
83
|
|
74
84
|
def condition_for_numeric(column, value)
|
75
85
|
if !value.is_a?(Hash)
|
76
|
-
["
|
86
|
+
["%{search_sql} = ?", condition_value_for_numeric(column, value)]
|
77
87
|
elsif value[:from].blank? or not ActiveScaffold::Finder::NumericComparators.include?(value[:opt])
|
78
88
|
nil
|
79
89
|
elsif value[:opt] == 'BETWEEN'
|
80
|
-
["
|
81
|
-
|
82
|
-
["
|
90
|
+
["(%{search_sql} BETWEEN ? AND ?)", condition_value_for_numeric(column, value[:from]), condition_value_for_numeric(column, value[:to])]
|
91
|
+
else
|
92
|
+
["%{search_sql} #{value[:opt]} ?", condition_value_for_numeric(column, value[:from])]
|
83
93
|
end
|
84
94
|
end
|
85
95
|
|
86
96
|
def condition_for_range(column, value, like_pattern = nil)
|
87
97
|
if !value.is_a?(Hash)
|
88
98
|
if column.column.nil? || column.column.text?
|
89
|
-
["
|
99
|
+
["%{search_sql} #{ActiveScaffold::Finder.like_operator} ?", like_pattern.sub('?', value)]
|
90
100
|
else
|
91
|
-
["
|
101
|
+
["%{search_sql} = ?", column.column.type_cast(value)]
|
92
102
|
end
|
93
103
|
elsif ActiveScaffold::Finder::NullComparators.include?(value[:opt])
|
94
104
|
condition_for_null_type(column, value[:opt], like_pattern)
|
95
105
|
elsif value[:from].blank?
|
96
106
|
nil
|
97
107
|
elsif ActiveScaffold::Finder::StringComparators.values.include?(value[:opt])
|
98
|
-
["
|
108
|
+
["%{search_sql} #{ActiveScaffold::Finder.like_operator} ?", value[:opt].sub('?', value[:from])]
|
99
109
|
elsif value[:opt] == 'BETWEEN'
|
100
|
-
["
|
110
|
+
["(%{search_sql} BETWEEN ? AND ?)", value[:from], value[:to]]
|
101
111
|
elsif ActiveScaffold::Finder::NumericComparators.include?(value[:opt])
|
102
|
-
["
|
112
|
+
["%{search_sql} #{value[:opt]} ?", value[:from]]
|
103
113
|
else
|
104
114
|
nil
|
105
115
|
end
|
@@ -157,37 +167,45 @@ module ActiveScaffold
|
|
157
167
|
value
|
158
168
|
end
|
159
169
|
end
|
170
|
+
|
171
|
+
def datetime_conversion_for_condition(column)
|
172
|
+
if column.column
|
173
|
+
column.column.type == :date ? :to_date : :to_time
|
174
|
+
else
|
175
|
+
:to_time
|
176
|
+
end
|
177
|
+
end
|
160
178
|
|
161
179
|
def condition_for_datetime(column, value, like_pattern = nil)
|
162
|
-
conversion = column
|
180
|
+
conversion = datetime_conversion_for_condition(column)
|
163
181
|
from_value = condition_value_for_datetime(value[:from], conversion)
|
164
182
|
to_value = condition_value_for_datetime(value[:to], conversion)
|
165
183
|
|
166
184
|
if from_value.nil? and to_value.nil?
|
167
185
|
nil
|
168
186
|
elsif !from_value
|
169
|
-
["
|
187
|
+
["%{search_sql} <= ?", to_value.to_s(:db)]
|
170
188
|
elsif !to_value
|
171
|
-
["
|
189
|
+
["%{search_sql} >= ?", from_value.to_s(:db)]
|
172
190
|
else
|
173
|
-
["
|
191
|
+
["%{search_sql} BETWEEN ? AND ?", from_value.to_s(:db), to_value.to_s(:db)]
|
174
192
|
end
|
175
193
|
end
|
176
194
|
|
177
195
|
def condition_for_record_select_type(column, value, like_pattern = nil)
|
178
196
|
if value.is_a?(Array)
|
179
|
-
["
|
197
|
+
["%{search_sql} IN (?)", value]
|
180
198
|
else
|
181
|
-
["
|
199
|
+
["%{search_sql} = ?", value]
|
182
200
|
end
|
183
201
|
end
|
184
202
|
|
185
203
|
def condition_for_null_type(column, value, like_pattern = nil)
|
186
204
|
case value.to_sym
|
187
205
|
when :null
|
188
|
-
["
|
206
|
+
["%{search_sql} is null", []]
|
189
207
|
when :not_null
|
190
|
-
["
|
208
|
+
["%{search_sql} is not null", []]
|
191
209
|
else
|
192
210
|
nil
|
193
211
|
end
|
@@ -218,8 +236,8 @@ module ActiveScaffold
|
|
218
236
|
:ends_with => '%?'
|
219
237
|
}
|
220
238
|
NullComparators = [
|
221
|
-
|
222
|
-
|
239
|
+
'null',
|
240
|
+
'not_null'
|
223
241
|
]
|
224
242
|
|
225
243
|
|
@@ -73,8 +73,11 @@ module ActiveScaffold
|
|
73
73
|
# Fix for keeping unique IDs in subform
|
74
74
|
id_control = "record_#{column.name}_#{[params[:eid], params[:id]].compact.join '_'}"
|
75
75
|
id_control += scope_id(scope) if scope
|
76
|
+
|
77
|
+
classes = "#{column.name}-input"
|
78
|
+
classes += ' numeric-input' if column.number?
|
76
79
|
|
77
|
-
{ :name => name, :class =>
|
80
|
+
{ :name => name, :class => classes, :id => id_control}.merge(options)
|
78
81
|
end
|
79
82
|
|
80
83
|
def update_columns_options(column, scope, options)
|
@@ -179,10 +179,12 @@ module ActiveScaffold
|
|
179
179
|
options_for_select(select_options, opt_value),
|
180
180
|
:id => "#{options[:id]}_opt",
|
181
181
|
:class => "as_search_range_option")
|
182
|
-
html <<
|
183
|
-
|
182
|
+
html << content_tag("span", :id => "#{options[:id]}_numeric", :style => ActiveScaffold::Finder::NullComparators.include?(opt_value) ? "display: none" : nil) do
|
183
|
+
text_field_tag("#{options[:name]}[from]", from_value, active_scaffold_input_text_options(:id => options[:id], :size => text_field_size)) <<
|
184
|
+
content_tag(:span, (' - ' + text_field_tag("#{options[:name]}[to]", to_value,
|
184
185
|
active_scaffold_input_text_options(:id => "#{options[:id]}_to", :size => text_field_size))).html_safe,
|
185
186
|
:id => "#{options[:id]}_between", :class => "as_search_range_between", :style => (opt_value == 'BETWEEN') ? nil : "display: none")
|
187
|
+
end
|
186
188
|
content_tag :span, html, :class => 'search_range'
|
187
189
|
end
|
188
190
|
alias_method :active_scaffold_search_integer, :active_scaffold_search_range
|
@@ -146,6 +146,7 @@ module ActiveScaffold
|
|
146
146
|
html_options[:data][:confirm] = link.confirm(record.try(:to_label)) if link.confirm?
|
147
147
|
html_options[:data][:position] = link.position if link.position and link.inline?
|
148
148
|
html_options[:data][:action] = link.action if link.inline?
|
149
|
+
html_options[:data][:'cancel-refresh'] = true if link.inline? and link.refresh_on_close
|
149
150
|
if link.popup?
|
150
151
|
html_options[:data][:popup] = true
|
151
152
|
html_options[:target] = '_blank'
|
@@ -189,11 +190,13 @@ module ActiveScaffold
|
|
189
190
|
end
|
190
191
|
|
191
192
|
def url_options_for_nested_link(column, record, link, url_options, options = {})
|
192
|
-
if column && column.association
|
193
|
+
if column && column.association
|
194
|
+
url_options[:parent_scaffold] = controller_path
|
193
195
|
url_options[column.association.active_record.name.foreign_key.to_sym] = url_options.delete(:id)
|
194
196
|
url_options[:id] = record.send(column.association.name).id if column.singular_association? && record.send(column.association.name).present?
|
195
197
|
url_options[:eid] = nil # needed for nested scaffolds open from an embedded scaffold
|
196
198
|
elsif link.parameters && link.parameters[:named_scope]
|
199
|
+
url_options[:parent_scaffold] = controller_path
|
197
200
|
url_options[active_scaffold_config.model.name.foreign_key.to_sym] = url_options.delete(:id)
|
198
201
|
url_options[:eid] = nil # needed for nested scaffolds open from an embedded scaffold
|
199
202
|
end
|
@@ -46,7 +46,6 @@ class ActiveScaffold::Tableless < ActiveRecord::Base
|
|
46
46
|
|
47
47
|
def self.columns; @columns ||= []; end
|
48
48
|
def self.table_name; @table_name ||= ActiveModel::Naming.plural(self); end
|
49
|
-
def self.connection; nil; end
|
50
49
|
def self.table_exists?; true; end
|
51
50
|
self.abstract_class = true
|
52
51
|
class << self
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_scaffold
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 3
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 3.2.
|
9
|
+
- 13
|
10
|
+
version: 3.2.13
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Many, see README
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-07-03 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
type: :development
|
@@ -29,8 +29,8 @@ dependencies:
|
|
29
29
|
- 0
|
30
30
|
version: "0"
|
31
31
|
version_requirements: *id001
|
32
|
-
prerelease: false
|
33
32
|
name: shoulda
|
33
|
+
prerelease: false
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
35
|
type: :development
|
36
36
|
requirement: &id002 !ruby/object:Gem::Requirement
|
@@ -45,8 +45,8 @@ dependencies:
|
|
45
45
|
- 0
|
46
46
|
version: 1.0.0
|
47
47
|
version_requirements: *id002
|
48
|
-
prerelease: false
|
49
48
|
name: bundler
|
49
|
+
prerelease: false
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
51
|
type: :development
|
52
52
|
requirement: &id003 !ruby/object:Gem::Requirement
|
@@ -59,8 +59,8 @@ dependencies:
|
|
59
59
|
- 0
|
60
60
|
version: "0"
|
61
61
|
version_requirements: *id003
|
62
|
-
prerelease: false
|
63
62
|
name: rcov
|
63
|
+
prerelease: false
|
64
64
|
- !ruby/object:Gem::Dependency
|
65
65
|
type: :runtime
|
66
66
|
requirement: &id004 !ruby/object:Gem::Requirement
|
@@ -75,8 +75,8 @@ dependencies:
|
|
75
75
|
- 3
|
76
76
|
version: 3.1.3
|
77
77
|
version_requirements: *id004
|
78
|
-
prerelease: false
|
79
78
|
name: rails
|
79
|
+
prerelease: false
|
80
80
|
description: Save time and headaches, and create a more easily maintainable set of pages, with ActiveScaffold. ActiveScaffold handles all your CRUD (create, read, update, delete) user interface needs, leaving you more time to focus on more challenging (and interesting!) problems.
|
81
81
|
email: activescaffold@googlegroups.com
|
82
82
|
executables: []
|
@@ -274,6 +274,7 @@ files:
|
|
274
274
|
- lib/active_scaffold/data_structures/sorting.rb
|
275
275
|
- lib/active_scaffold/engine.rb
|
276
276
|
- lib/active_scaffold/extensions/action_controller_rendering.rb
|
277
|
+
- lib/active_scaffold/extensions/action_controller_rescueing.rb
|
277
278
|
- lib/active_scaffold/extensions/action_view_rendering.rb
|
278
279
|
- lib/active_scaffold/extensions/active_association_reflection.rb
|
279
280
|
- lib/active_scaffold/extensions/active_record_offset.rb
|
@@ -442,7 +443,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
442
443
|
requirements: []
|
443
444
|
|
444
445
|
rubyforge_project:
|
445
|
-
rubygems_version: 1.8.
|
446
|
+
rubygems_version: 1.8.10
|
446
447
|
signing_key:
|
447
448
|
specification_version: 3
|
448
449
|
summary: Rails 3.1 Version of activescaffold supporting prototype and jquery
|