admin_data 1.0.22 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. data/History.txt +23 -16
  2. data/README.md +1 -1
  3. data/Rakefile +2 -2
  4. data/app/controllers/admin_data/application_controller.rb +111 -0
  5. data/app/controllers/admin_data/crud_controller.rb +100 -0
  6. data/app/controllers/admin_data/feed_controller.rb +38 -16
  7. data/app/controllers/admin_data/home_controller.rb +11 -0
  8. data/app/controllers/admin_data/migration_controller.rb +12 -12
  9. data/app/controllers/admin_data/public_controller.rb +29 -19
  10. data/app/controllers/admin_data/search_controller.rb +99 -103
  11. data/app/controllers/admin_data/table_structure_controller.rb +25 -0
  12. data/app/helpers/admin_data/application_helper.rb +287 -0
  13. data/app/views/admin_data/crud/association/_association_info.html.erb +11 -0
  14. data/app/views/admin_data/crud/association/_belongs_to_info.html.erb +7 -0
  15. data/app/views/admin_data/{main → crud}/association/_habtm_info.html.erb +3 -3
  16. data/app/views/admin_data/{main → crud}/association/_has_many_info.html.erb +3 -3
  17. data/app/views/admin_data/crud/association/_has_one_info.html.erb +6 -0
  18. data/app/views/admin_data/{main → crud}/edit.html.erb +9 -9
  19. data/app/views/admin_data/{main → crud}/misc/_form.html.erb +6 -6
  20. data/app/views/admin_data/{main → crud}/misc/_modify_record.html.erb +4 -4
  21. data/app/views/admin_data/{main → crud}/new.html.erb +7 -7
  22. data/app/views/admin_data/{main → crud}/show.html.erb +10 -10
  23. data/app/views/admin_data/{main → home}/index.html.erb +2 -2
  24. data/app/views/admin_data/migration/index.html.erb +3 -3
  25. data/app/views/admin_data/search/_search_base.html.erb +5 -5
  26. data/app/views/admin_data/search/quick_search.html.erb +4 -4
  27. data/app/views/admin_data/search/search/_listing.html.erb +11 -9
  28. data/app/views/admin_data/search/search/_sortby.html.erb +4 -3
  29. data/app/views/admin_data/search/search/_title.html.erb +7 -7
  30. data/app/views/admin_data/shared/_breadcrum.html.erb +11 -5
  31. data/app/views/admin_data/shared/_header.html.erb +6 -6
  32. data/app/views/admin_data/shared/_secondary_navigation.html.erb +13 -14
  33. data/app/views/admin_data/{main/table_structure.html.erb → table_structure/index.html.erb} +11 -11
  34. data/app/views/layouts/admin_data.html.erb +15 -15
  35. data/config/routes.rb +3 -3
  36. data/lib/admin_data.rb +29 -6
  37. data/lib/admin_data/active_record_util.rb +38 -6
  38. data/lib/admin_data/configuration.rb +113 -0
  39. data/lib/admin_data/deprecation.rb +31 -0
  40. data/lib/admin_data/railtie.rb +2 -7
  41. data/lib/admin_data/search.rb +1 -1
  42. data/lib/admin_data/util.rb +74 -161
  43. data/lib/admin_data/version.rb +1 -1
  44. data/test/rails_root/app/controllers/application_controller.rb +3 -0
  45. data/test/rails_root/app/helpers/application_helper.rb +5 -0
  46. data/test/rails_root/app/models/city.rb +22 -0
  47. data/test/rails_root/app/models/club.rb +3 -0
  48. data/test/rails_root/app/models/newspaper.rb +4 -0
  49. data/test/rails_root/app/models/phone_number.rb +3 -0
  50. data/test/rails_root/app/models/user.rb +17 -0
  51. data/test/rails_root/app/models/website.rb +3 -0
  52. data/test/rails_root/config/application.rb +42 -0
  53. data/test/rails_root/config/boot.rb +13 -0
  54. data/test/rails_root/config/environment.rb +5 -0
  55. data/test/rails_root/config/environments/development.rb +22 -0
  56. data/test/rails_root/config/environments/production.rb +49 -0
  57. data/test/rails_root/config/environments/test.rb +35 -0
  58. data/test/rails_root/config/initializers/admin_data.rb +22 -0
  59. data/test/rails_root/config/initializers/backtrace_silencers.rb +7 -0
  60. data/test/rails_root/config/initializers/empty_spaces_to_nil.rb +10 -0
  61. data/test/rails_root/config/initializers/inflections.rb +10 -0
  62. data/test/rails_root/config/initializers/mime_types.rb +5 -0
  63. data/test/rails_root/config/initializers/secret_token.rb +7 -0
  64. data/test/rails_root/config/initializers/session_store.rb +8 -0
  65. data/test/rails_root/config/routes.rb +9 -0
  66. data/test/rails_root/db/migrate/20091030202259_create_users.rb +55 -0
  67. data/test/rails_root/db/schema.rb +63 -0
  68. data/test/rails_root/db/seeds.rb +40 -0
  69. data/test/rails_root/features/step_definitions/advance_search_steps.rb +13 -0
  70. data/test/rails_root/features/step_definitions/app_steps.rb +40 -0
  71. data/test/rails_root/features/step_definitions/async.rb +18 -0
  72. data/test/rails_root/features/step_definitions/crud_show_steps.rb +37 -0
  73. data/test/rails_root/features/step_definitions/feed_steps.rb +3 -0
  74. data/test/rails_root/features/step_definitions/quick_search_steps.rb +65 -0
  75. data/test/rails_root/features/step_definitions/util.rb +86 -0
  76. data/test/rails_root/features/step_definitions/web_steps.rb +219 -0
  77. data/test/rails_root/features/support/env.rb +68 -0
  78. data/test/rails_root/features/support/paths.rb +33 -0
  79. data/test/rails_root/test/factories.rb +30 -0
  80. data/test/rails_root/test/performance/browsing_test.rb +9 -0
  81. data/test/rails_root/test/test_helper.rb +13 -0
  82. metadata +100 -49
  83. data/app/controllers/admin_data/base_controller.rb +0 -112
  84. data/app/controllers/admin_data/main_controller.rb +0 -141
  85. data/app/views/admin_data/main/association/_association_info.html.erb +0 -11
  86. data/app/views/admin_data/main/association/_belongs_to_info.html.erb +0 -7
  87. data/app/views/admin_data/main/association/_has_one_info.html.erb +0 -6
  88. data/lib/admin_data/chelper.rb +0 -37
  89. data/lib/admin_data/helpers.rb +0 -271
  90. data/lib/admin_data/settings.rb +0 -67
  91. data/lib/css/base.css +0 -1108
  92. data/lib/css/vendor/jquery-ui-1.7.2.custom.css +0 -406
  93. data/lib/js/advance_search/act_on_result.js +0 -45
  94. data/lib/js/advance_search/advance_search.js +0 -83
  95. data/lib/js/advance_search/advance_search_structure.js +0 -79
  96. data/lib/js/advance_search/ajaxify_advance_search.js +0 -28
  97. data/lib/js/advance_search/build_first_row.js +0 -8
  98. data/lib/js/advance_search/event_bindings.js +0 -76
  99. data/lib/js/advance_search/global_ajax_setting.js +0 -10
  100. data/lib/js/advance_search/trigger_submit_on_domready.js +0 -6
  101. data/lib/js/misc/drop_down_change.js +0 -8
  102. data/lib/js/misc/js_util.js +0 -58
  103. data/lib/js/misc/quick_search_input_focus.js +0 -6
  104. data/lib/js/test/act_on_result.js +0 -120
  105. data/lib/js/test/advance_search.js +0 -80
  106. data/lib/js/test/ajaxify_advance_search.js +0 -29
  107. data/lib/js/test/build_first_row.js +0 -10
  108. data/lib/js/test/event_bindings.js +0 -100
  109. data/lib/js/vendor/jack.js +0 -903
  110. data/lib/js/vendor/jquery-1.4.2.js +0 -6240
  111. data/lib/js/vendor/jquery-ui-1.7.2.custom.min.js +0 -298
  112. data/lib/js/vendor/jquery.ba-isjquery.js +0 -21
  113. data/lib/js/vendor/jquery.form.js +0 -814
  114. data/lib/js/vendor/log.js +0 -9
  115. data/lib/js/vendor/qunit.js +0 -1043
  116. data/lib/js/vendor/rails.js +0 -132
@@ -1,27 +1,37 @@
1
+ module AdminData
2
+ class PublicController < ApplicationController
1
3
 
2
- class AdminData::PublicController < AdminData::BaseController
4
+ def serve
3
5
 
4
- def serve
5
- f = File.join(AdminData::Config.setting[:plugin_dir], 'lib', params[:file])
6
+ # validate filename with a white list
7
+ unless self.class.admin_data_assets.include? params[:file]
8
+ render :nothing => true, :status => 404 and return
9
+ end
6
10
 
7
- unless File.exists?(f)
8
- render :nothing => true, :status => 404 and return
11
+ opts = {:text => File.read(File.join(AdminData.public_dir,params[:file])), :cache => true}
12
+
13
+ case params[:file]
14
+ when /\.css$/i then opts[:content_type] = "text/css"
15
+ when /\.js$/i then opts[:content_type] = "text/javascript"
16
+ when /\.png$/i then opts[:content_type] = "image/png"
17
+ else
18
+ render :nothing => true, :status => 404 and return
19
+ end
20
+
21
+ render opts
9
22
  end
10
23
 
11
- opts = {:text => File.new(f).read, :cache => true}
12
- if f =~ /css$/
13
- opts[:content_type] = "text/css"
14
- elsif f =~ /js$/
15
- opts[:content_type] = "text/javascript"
16
- else
17
- # this is needed so that a user is not able to get data by performing url like
18
- # http://localhost:3000/admin_data/public/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd
19
- # Above url will try to get /etc/passwd
20
- #
21
- # ensures that request file must end with js or css
22
- render :nothing => true, :status => 404 and return
24
+ protected
25
+
26
+ # Cached list of all assets provided by admin_data
27
+ # It is used to ensure security in the serve method
28
+ def self.admin_data_assets
29
+ @admin_data_assets ||= (
30
+ Dir.glob(File.join(AdminData.public_dir,'**','*')).map do |path|
31
+ # we want only relative paths
32
+ path = path.split(AdminData.public_dir,2).last
33
+ end
34
+ )
23
35
  end
24
- render opts
25
36
  end
26
-
27
37
  end
@@ -1,125 +1,121 @@
1
- require File.join(File.dirname(__FILE__) , '..', '..', '..', 'lib', 'admin_data', 'search')
2
-
3
- class AdminData::SearchController < AdminData::BaseController
4
-
5
- include Search
6
-
7
- unloadable
8
-
9
- before_filter :get_class_from_params
10
- before_filter :ensure_is_allowed_to_view
11
- before_filter :ensure_is_allowed_to_view_klass
12
- before_filter :ensure_valid_children_klass, :only => [:quick_search]
13
- before_filter :ensure_is_authorized_for_update_opration, :only => [:advance_search]
14
- before_filter :set_column_type_info, :only => [:advance_search]
15
-
16
- def quick_search
17
- @page_title = "Search #{@klass.name.underscore}"
18
- @order = default_order
19
-
20
- if params[:base]
21
- klass = AdminData::Util.camelize_constantize(params[:base])
22
- model = klass.find(params[:model_id])
23
- has_many_proxy = model.send(params[:children].intern)
24
- @total_num_of_children = has_many_proxy.send(:count)
25
- h = { :page => params[:page], :per_page => per_page, :order => @order }
26
- @records = has_many_proxy.send(:paginate, h)
27
- else
28
- params[:query] = params[:query].strip unless params[:query].blank?
29
- cond = build_quick_search_conditions(@klass, params[:query])
30
- h = { :page => params[:page], :per_page => per_page, :order => @order, :conditions => cond }
31
- @records = @klass.unscoped.paginate(h)
1
+ require File.join(AdminData::LIBPATH, 'admin_data', 'search')
2
+
3
+ module AdminData
4
+ class SearchController < ApplicationController
5
+
6
+ include Search
7
+
8
+ before_filter :get_class_from_params
9
+ before_filter :ensure_valid_children_klass, :only => [:quick_search]
10
+ before_filter :ensure_is_authorized_for_update_opration, :only => [:advance_search]
11
+ before_filter :set_column_type_info, :only => [:advance_search]
12
+
13
+ def quick_search
14
+ @page_title = "Search #{@klass.name.underscore}"
15
+ @order = default_order
16
+
17
+ if params[:base]
18
+ klass = Util.camelize_constantize(params[:base])
19
+ model = klass.find(params[:model_id])
20
+ has_many_proxy = model.send(params[:children].intern)
21
+ @total_num_of_children = has_many_proxy.send(:count)
22
+ h = { :page => params[:page], :per_page => per_page, :order => @order }
23
+ @records = has_many_proxy.send(:paginate, h)
24
+ else
25
+ params[:query] = params[:query].strip unless params[:query].blank?
26
+ cond = build_quick_search_conditions(@klass, params[:query])
27
+ h = { :page => params[:page], :per_page => per_page, :order => @order, :conditions => cond }
28
+ @records = @klass.unscoped.paginate(h)
29
+ end
30
+ respond_to {|format| format.html}
32
31
  end
33
- respond_to {|format| format.html}
34
- end
35
32
 
36
33
 
37
- def advance_search
38
- @page_title = "Advance search #{@klass.name.underscore}"
39
- plugin_dir = AdminData::Config.setting[:plugin_dir]
40
- hash = build_advance_search_conditions(@klass, params[:adv_search])
41
- @relation = hash[:cond]
42
- errors = hash[:errors]
43
- @order = default_order
34
+ def advance_search
35
+ @page_title = "Advance search #{@klass.name.underscore}"
36
+ hash = build_advance_search_conditions(@klass, params[:adv_search])
37
+ @relation = hash[:cond]
38
+ errors = hash[:errors]
39
+ @order = default_order
40
+
41
+ respond_to do |format|
42
+ format.html { render }
43
+ format.js {
44
+
45
+ unless hash[:errors].blank?
46
+ file = "#{AdminData.plugin_dir}app/views/admin_data/search/search/_errors.html.erb"
47
+ render :file => file, :locals => {:errors => errors}
48
+ return
49
+ end
50
+ if params[:admin_data_advance_search_action_type] == 'destroy'
51
+ handle_advance_search_action_type_destroy
52
+ elsif params[:admin_data_advance_search_action_type] == 'delete'
53
+ handle_advance_search_action_type_delete
54
+ else
55
+ @records = @relation.order(@order).paginate(:page => params[:page], :per_page => per_page)
56
+ end
57
+
58
+ if @success_message
59
+ render :json => {:success => @success_message }
60
+ else
61
+ file = "/admin_data/search/search/listing.html.erb"
62
+ render :partial => file, :locals => {:klass => @klass}, :layout => false
63
+ end
64
+ }
65
+ end
66
+ end
44
67
 
45
- respond_to do |format|
46
- format.html { render }
47
- format.js {
68
+ private
48
69
 
49
- unless hash[:errors].blank?
50
- file = "#{plugin_dir}/app/views/admin_data/search/search/_errors.html.erb"
51
- render :file => file, :locals => {:errors => errors}
70
+ def ensure_valid_children_klass
71
+ if params[:base]
72
+ begin
73
+ model_klass = Util.camelize_constantize(params[:base])
74
+ rescue NameError => e #incase params[:base] is junk value
75
+ render :text => "#{params[:base]} is an invalid value", :status => :not_found
52
76
  return
53
77
  end
54
- if params[:admin_data_advance_search_action_type] == 'destroy'
55
- handle_advance_search_action_type_destroy
56
- elsif params[:admin_data_advance_search_action_type] == 'delete'
57
- handle_advance_search_action_type_delete
78
+ if ActiveRecordUtil.declared_has_many_association_names(model_klass).include?(params[:children]) || ActiveRecordUtil.declared_habtm_association_names(model_klass).include?(params[:children])
79
+ #proceed
58
80
  else
59
- @records = @relation.order(@order).paginate(:page => params[:page], :per_page => per_page)
60
- end
61
-
62
- if @success_message
63
- render :json => {:success => @success_message }
64
- else
65
- file = "/admin_data/search/search/listing.html.erb"
66
- render :partial => file, :locals => {:klass => @klass}, :layout => false
81
+ render :text => "#{params[:children]} is not a valid has_many association", :status => :not_found
82
+ return
67
83
  end
68
- }
84
+ end
69
85
  end
70
- end
71
86
 
72
- private
73
-
74
- def ensure_valid_children_klass
75
- if params[:base]
76
- begin
77
- model_klass = AdminData::Util.camelize_constantize(params[:base])
78
- rescue NameError => e #incase params[:base] is junk value
79
- render :text => "#{params[:base]} is an invalid value", :status => :not_found
80
- return
81
- end
82
- #TODO write test for this condition
83
- if AdminData::ActiveRecordUtil.declared_has_many_association_names(model_klass).include?(params[:children]) || AdminData::ActiveRecordUtil.declared_habtm_association_names(model_klass).include?(params[:children])
84
- #proceed
85
- else
86
- render :text => "#{params[:children]} is not a valid has_many association", :status => :not_found
87
- return
87
+ def ensure_is_authorized_for_update_opration
88
+ if %w(destroy delete).include? params[:admin_data_advance_search_action_type]
89
+ render :text => 'not authorized' unless is_allowed_to_update?
88
90
  end
89
91
  end
90
- end
91
92
 
92
- def ensure_is_authorized_for_update_opration
93
- if %w(destroy delete).include? params[:admin_data_advance_search_action_type]
94
- render :text => 'not authorized' unless admin_data_is_allowed_to_update?
93
+ def handle_advance_search_action_type_delete
94
+ count = @relation.count
95
+ @relation.delete_all
96
+ @success_message = "#{count} #{Util.pluralize(count, 'record')} deleted"
95
97
  end
96
- end
97
98
 
98
- def handle_advance_search_action_type_delete
99
- count = @relation.count
100
- @relation.delete_all
101
- @success_message = "#{count} #{AdminData::Util.pluralize(count, 'record')} deleted"
102
- end
99
+ def handle_advance_search_action_type_destroy
100
+ count = @relation.count
101
+ @relation.find_in_batches do |group|
102
+ group.each {|record| record.destroy }
103
+ end
104
+ @success_message = "#{count} #{Util.pluralize(count, 'record')} destroyed"
105
+ end
103
106
 
104
- def handle_advance_search_action_type_destroy
105
- count = @relation.count
106
- @relation.find_in_batches do |group|
107
- group.each {|record| record.destroy }
107
+ def default_order
108
+ params[:sortby] || "#{@klass.send(:table_name)}.#{@klass.send(:primary_key)} desc"
108
109
  end
109
- @success_message = "#{count} #{AdminData::Util.pluralize(count, 'record')} destroyed"
110
- end
111
110
 
112
- def default_order
113
- params[:sortby] || "#{@klass.send(:table_name)}.#{@klass.send(:primary_key)} desc"
114
- end
111
+ def set_column_type_info
112
+ column_type_info = @klass.columns.collect { |column|
113
+ #JSLint complains if a hash has key named boolean. So I am changing the key to booleant
114
+ column_type = (column.type.to_s == 'boolean') ? 'booleant' : column.type.to_s
115
+ %Q{ "#{column.name}":"#{column_type}" }
116
+ }.join(',')
117
+ @column_type_info = "{#{column_type_info}}"
118
+ end
115
119
 
116
- def set_column_type_info
117
- column_type_info = @klass.columns.collect { |column|
118
- #JSLint complains if a hash has key named boolean. So I am changing the key to booleant
119
- column_type = (column.type.to_s == 'boolean') ? 'booleant' : column.type.to_s
120
- %Q{ "#{column.name}":"#{column_type}" }
121
- }.join(',')
122
- @column_type_info = "{#{column_type_info}}"
123
120
  end
124
-
125
121
  end
@@ -0,0 +1,25 @@
1
+ module AdminData
2
+ class TableStructureController < ApplicationController
3
+
4
+ before_filter :get_class_from_params
5
+
6
+ def index
7
+ @page_title = 'table_structure'
8
+ @indexes = []
9
+ if (indexes = ActiveRecord::Base.connection.indexes(@klass.table_name)).any?
10
+ add_index_statements = indexes.map do |index|
11
+ statment_parts = [ ('add_index ' + index.table.inspect) ]
12
+ statment_parts << index.columns.inspect
13
+ statment_parts << (':name => ' + index.name.inspect)
14
+ statment_parts << ':unique => true' if index.unique
15
+
16
+ ' ' + statment_parts.join(', ')
17
+ end
18
+ add_index_statements.sort.each { |index| @indexes << index }
19
+ end
20
+ respond_to {|format| format.html}
21
+ end
22
+
23
+ end
24
+ end
25
+
@@ -0,0 +1,287 @@
1
+ module AdminData
2
+ module ApplicationHelper
3
+
4
+ def column_title(klass, column)
5
+ AdminData.config.column_headers[klass.name].try(:fetch,column.intern, nil) || column
6
+ end
7
+
8
+ # AdminData.config.columns_order might not list all the columns of a given table. However
9
+ # the listed columns should be at the front in the order mentioned. Primary key will also
10
+ # be the first column. Consumer might define a new column name that is not listed a column.
11
+ #
12
+ def columns_order(klass)
13
+ columns_symbol = klass.columns.map {|e| e.name.intern}
14
+
15
+ # created_at and updated_at should be at the very end by default
16
+ if columns_symbol.include? :created_at
17
+ columns_symbol = (columns_symbol - [:created_at]) + [:created_at]
18
+ end
19
+ if columns_symbol.include? :updated_at
20
+ columns_symbol = (columns_symbol - [:updated_at]) + [:updated_at]
21
+ end
22
+
23
+ if requested_order = AdminData.config.columns_order[klass.name]
24
+ primary_key = klass.send(:primary_key).intern
25
+ order = [primary_key] + requested_order
26
+ order.uniq!
27
+ # add the columns not covered by user at the end of the list
28
+ sorted_columns = order + (columns_symbol - order)
29
+ sorted_columns.map(&:to_s)
30
+ else
31
+ columns_symbol.map(&:to_s)
32
+ end
33
+ end
34
+
35
+ def total_records_info(klass)
36
+ '(Total ' + pluralize(klass.count, 'record') + ' )'
37
+ end
38
+
39
+ def search_result_title(total_num_of_children, records)
40
+ output = []
41
+ if params[:base]
42
+ label = params[:base].camelize + ' ID ' + params[:model_id]
43
+ output << link_to(label, admin_data_path(:klass => params[:base], :id => params[:model_id]))
44
+ output << 'has'
45
+ output << pluralize(total_num_of_children, params[:klass])
46
+
47
+ elsif !params[:query].blank? || params[:adv_search]
48
+ output << 'Search result:'
49
+ output << pluralize(records.total_entries, 'record')
50
+ output << 'found'
51
+
52
+ else
53
+ output << 'All '
54
+ output << params[:klass].camelize
55
+ output << 'records'
56
+ end
57
+ output.join(' ').html_safe
58
+ end
59
+
60
+ def column_native(klass, column)
61
+ klass.send(:columns).select {|r| r.instance_variable_get('@name') == column}.first || column
62
+ end
63
+
64
+ def has_one(model, klass)
65
+ tmp = AdminData::ActiveRecordUtil.declared_has_one_association_names(klass)
66
+ tmp.inject('') do |output, ho|
67
+ begin
68
+ label = ho
69
+ if model.send(ho)
70
+ output << link_to(label, admin_data_path(:klass => ho.underscore, :id => model.send(ho)))
71
+ else
72
+ output << label
73
+ end
74
+ rescue => e
75
+ Rails.logger.debug AdminData::Util.exception_info(e)
76
+ end
77
+ output
78
+ end
79
+ end
80
+
81
+ def has_many_data(model, klass)
82
+ array = AdminData::ActiveRecordUtil.declared_has_many_association_names(klass).map do |m|
83
+ begin
84
+ count = model.send(m.intern).count
85
+ label = m.to_s + '(' + count.to_s + ')'
86
+ output = label
87
+ if count > 0
88
+ has_many_klass_name = AdminData::ActiveRecordUtil.klass_for_association_type_and_name(model.class, :has_many, m).name.underscore
89
+ output = link_to(label, admin_data_search_path( :klass => has_many_klass_name,
90
+ :children => m,
91
+ :base => klass.name.underscore,
92
+ :model_id => model.id))
93
+ end
94
+ rescue => e
95
+ Rails.logger.debug AdminData::Util.exception_info(e)
96
+ end
97
+ output
98
+ end
99
+ array.join(', ')
100
+ end
101
+
102
+ def belongs_to_data(model, klass)
103
+ AdminData::ActiveRecordUtil.declared_belongs_to_association_names(klass).map do |assoc_name|
104
+ begin
105
+ output = assoc_name
106
+ if belongs_to_record = model.send(assoc_name)
107
+ output = link_to(assoc_name, admin_data_path(:klass => belongs_to_record.class.name.underscore, :id => belongs_to_record.id))
108
+ end
109
+ rescue => e
110
+ Rails.logger.info AdminData::Util.exception_info(e)
111
+ end
112
+ output
113
+ end.join(', ')
114
+ end
115
+
116
+ def habtm_data(model, klass)
117
+ AdminData::ActiveRecordUtil.declared_habtm_association_names(klass).map do |assoc_name|
118
+ begin
119
+ count = model.send(assoc_name.intern).count
120
+ label = assoc_name + '(' + count.to_s + ')'
121
+ output = label
122
+
123
+ if count > 0 then
124
+ has_many_klass_name = AdminData::ActiveRecordUtil.klass_for_association_type_and_name(model.class, :has_and_belongs_to_many, assoc_name).name.underscore
125
+ output = link_to(label, admin_data_search_path( :klass => has_many_klass_name,
126
+ :children => assoc_name,
127
+ :base => klass.name.underscore,
128
+ :model_id => model.id))
129
+ end
130
+ rescue => e
131
+ Rails.logger.info AdminData::Util.exception_info(e)
132
+ end
133
+ output
134
+ end.join(', ')
135
+ end
136
+
137
+ def breadcrum(&block)
138
+ render(:partial => '/admin_data/shared/breadcrum', :locals => {:data => capture(&block)})
139
+ end
140
+
141
+ def form_field(klass, model, col, f)
142
+ html = []
143
+ column_value = model.send(col.name)
144
+
145
+ if klass.serialized_attributes.has_key?(col.name)
146
+ return AdminData::Util.get_serialized_value(html,column_value)
147
+ end
148
+
149
+ if col.primary
150
+ html << model.new_record? ? '(auto)' : model.id
151
+ elsif get_reflection_for_column(klass, col) && AdminData.config.drop_down_for_associations[klass.name]
152
+ form_field_for_association_records(klass, col, f, html)
153
+ else
154
+ handle_column_type(col, html, model, column_value, f)
155
+ end
156
+ end
157
+
158
+
159
+ def form_field_for_association_records(klass, col, f, html)
160
+ begin
161
+ reflection = get_reflection_for_column(klass, col)
162
+
163
+ # in some edge cases following code throws exception. investigating ..
164
+ options = reflection.options
165
+ if options.keys.include?(:polymorphic) && options.fetch(:polymorphic)
166
+ build_text_field(html, f, col)
167
+ else
168
+ ref_klass = reflection.klass
169
+ association_name = ref_klass.columns.map(&:name).include?('name') ? :name : ref_klass.primary_key
170
+ all_for_dropdown = ref_klass.all(:order => "#{association_name} asc")
171
+ html << f.collection_select(col.name, all_for_dropdown, :id, association_name, :include_blank => true)
172
+ end
173
+ html.join
174
+ rescue Exception => e
175
+ Rails.logger.info AdminData::Util.exception_info(e)
176
+ 'could not retrieve' # returning nil
177
+ end
178
+ end
179
+
180
+ def form_field_for_habtm_records(klass, model, f, html)
181
+ begin
182
+ html = []
183
+ AdminData::ActiveRecordUtil.delcared_habtm_association_names(klass).each do |k|
184
+ assoc_klass = AdminData::Util.get_class_name_for_habtm_association(model, k)
185
+
186
+ html << "<div class='col_box'>"
187
+ html << " <span class='col_name'>#{assoc_klass.table_name}</span>"
188
+ html << " <span class='col_type'>[integer]</span>"
189
+ html << "</div>"
190
+
191
+ order_by = assoc_klass.columns.map(&:name).include?('name') ? :name : assoc_klass.primary_key
192
+ all = assoc_klass.all(:order => order_by)
193
+ selected = model.send(assoc_klass.table_name).map{|e| e.id}
194
+ html << f.collection_select(assoc_klass.table_name, all, :id, order_by,
195
+ {:include_blank => false, :selected => selected},
196
+ {:multiple => true, :size => (all.count > 10 ? 8 : 4)})
197
+ end
198
+ html.join
199
+ rescue Exception => e
200
+ Rails.logger.info AdminData::Util.exception_info(e)
201
+ 'could not retrieve' # returning nil
202
+ end
203
+ end
204
+
205
+ def handle_column_type(col, html, model, column_value, f)
206
+ case col.type
207
+ when :text
208
+ html << f.text_area(col.name, :rows => 6, :cols => 70)
209
+
210
+ when :datetime
211
+ if ['created_at', 'updated_at'].include?(col.name)
212
+ html << '(auto)'
213
+ else
214
+ value = params[:action] == 'new' ? Time.now : column_value
215
+ year_value = value.year if value
216
+ datetime_selects = f.datetime_select(col.name, :include_blank => true)
217
+ html << datetime_selects.gsub('type="hidden"', 'type="text" size="4" class="nice-field"')
218
+ end
219
+
220
+ when :date
221
+ value = params[:action] == 'new' ? Time.now : column_value
222
+ year_value = value.year if value
223
+ date_selects = f.date_select(col.name, :discard_year => true, :include_blank => true)
224
+ html << date_selects.gsub('type="hidden"', 'type="text" size="4" class="nice-field"')
225
+
226
+ when :time
227
+ # time_select method of rails is buggy and is causing problem
228
+ # 1 error(s) on assignment of multiparameter attributes
229
+ #
230
+ # will try again this method with Rails 3
231
+ #html << f.time_select(col.name, :include_blank => true, :include_seconds => true)
232
+
233
+ when :boolean
234
+ html << f.select(col.name, [['True', true], ['False', false]], :include_blank => true)
235
+
236
+ else
237
+ build_text_field(html, f, col)
238
+ end
239
+ html.join
240
+ end
241
+
242
+
243
+ def build_text_field(html, f, col)
244
+ options = {:class => 'nice-field'}
245
+ if AdminData.config.ignore_column_limit
246
+ options[:size] = 60
247
+ options[:maxlength] = 255
248
+ else
249
+ options[:size] = (col && col.limit && col.limit < 60) ? col.limit : 60
250
+ options[:maxlength] = col.limit if col.limit
251
+ end
252
+ html << f.text_field(col.name, options)
253
+ html.join
254
+ end
255
+
256
+ # uses truncate method
257
+ # options supports :limit which is applied if the column type is string or text.
258
+ # calls the inspect method to convert to a string if the column is serialized.
259
+ # TODO rspec test limit option
260
+ def get_value_for_column(column, model, options = {})
261
+ options.reverse_merge!(:limit => 400)
262
+
263
+ value = AdminData::Util.custom_value_for_column(column, model)
264
+
265
+ if column.is_a?(String)
266
+ value
267
+ elsif column.type == :datetime
268
+ value.strftime('%d-%B-%Y %H:%M:%S %p') unless value.blank?
269
+ elsif column.type == :string || column.type == :text
270
+ value = value.inspect if model.class.serialized_attributes.keys.include?(column.name)
271
+ return value if options[:limit].blank?
272
+ begin
273
+ truncate(value,:length => options[:limit])
274
+ rescue # truncate method failed
275
+ '<actual data is not being shown because truncate method failed.>'
276
+ end
277
+ else
278
+ value.to_s
279
+ end
280
+ end
281
+
282
+ def get_reflection_for_column(klass, col)
283
+ klass.reflections.values.detect { |reflection| reflection.primary_key_name.to_sym == col.name.to_sym }
284
+ end
285
+
286
+ end
287
+ end