the_jobbook_admin_data 1.3.0a
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.
- data/.gitignore +19 -0
- data/CHANGELOG.rdoc +284 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +121 -0
- data/Guardfile +14 -0
- data/MIT-LICENSE +20 -0
- data/README.md +37 -0
- data/README.rdoc +3 -0
- data/Rakefile +40 -0
- data/admin_data.gemspec +23 -0
- data/app/assets/images/add.png +0 -0
- data/app/assets/images/admin_data/.gitkeep +0 -0
- data/app/assets/images/no.png +0 -0
- data/app/assets/images/site.png +0 -0
- data/app/assets/images/sort_by_asc.jpg +0 -0
- data/app/assets/images/sort_by_desc.jpg +0 -0
- data/app/assets/images/sort_by_nothing.jpg +0 -0
- data/app/assets/javascripts/admin_data.js +18 -0
- data/app/assets/javascripts/admin_data/application.js +15 -0
- data/app/assets/javascripts/advance_search/act_on_result.js +45 -0
- data/app/assets/javascripts/advance_search/advance_search.js +83 -0
- data/app/assets/javascripts/advance_search/advance_search_structure.js +79 -0
- data/app/assets/javascripts/advance_search/ajaxify_advance_search.js +28 -0
- data/app/assets/javascripts/advance_search/build_first_row.js +8 -0
- data/app/assets/javascripts/advance_search/event_bindings.js +76 -0
- data/app/assets/javascripts/advance_search/global_ajax_setting.js +10 -0
- data/app/assets/javascripts/advance_search/sortby.js +14 -0
- data/app/assets/javascripts/advance_search/trigger_submit_on_domready.js +6 -0
- data/app/assets/javascripts/analytics/report.js +7 -0
- data/app/assets/javascripts/misc/drop_down_change.js +8 -0
- data/app/assets/javascripts/misc/js_util.js +58 -0
- data/app/assets/javascripts/misc/quick_search_input_focus.js +6 -0
- data/app/assets/javascripts/vendor/jquery-1.4.2.js +6240 -0
- data/app/assets/javascripts/vendor/jquery-ui-1.7.2.custom.min.js +298 -0
- data/app/assets/javascripts/vendor/jquery.ba-isjquery.js +21 -0
- data/app/assets/javascripts/vendor/jquery_form.js +814 -0
- data/app/assets/javascripts/vendor/log.js +9 -0
- data/app/assets/javascripts/vendor/rails.js +132 -0
- data/app/assets/stylesheets/admin_data.css +1141 -0
- data/app/assets/stylesheets/admin_data/application.css +13 -0
- data/app/assets/stylesheets/vendor/jquery-ui-1.7.2.custom.css +406 -0
- data/app/controllers/admin_data/application_controller.rb +107 -0
- data/app/controllers/admin_data/crud_controller.rb +100 -0
- data/app/controllers/admin_data/feed_controller.rb +48 -0
- data/app/controllers/admin_data/home_controller.rb +8 -0
- data/app/controllers/admin_data/migration_controller.rb +18 -0
- data/app/controllers/admin_data/public_controller.rb +28 -0
- data/app/controllers/admin_data/search_controller.rb +143 -0
- data/app/controllers/admin_data/table_structure_controller.rb +25 -0
- data/app/helpers/admin_data/application_helper.rb +320 -0
- data/app/views/admin_data/crud/association/_association_info.html.erb +11 -0
- data/app/views/admin_data/crud/association/_belongs_to_info.html.erb +7 -0
- data/app/views/admin_data/crud/association/_habtm_info.html.erb +7 -0
- data/app/views/admin_data/crud/association/_has_many_info.html.erb +7 -0
- data/app/views/admin_data/crud/association/_has_one_info.html.erb +6 -0
- data/app/views/admin_data/crud/edit.html.erb +36 -0
- data/app/views/admin_data/crud/misc/_form.html.erb +38 -0
- data/app/views/admin_data/crud/misc/_modify_record.html.erb +18 -0
- data/app/views/admin_data/crud/new.html.erb +25 -0
- data/app/views/admin_data/crud/show.html.erb +42 -0
- data/app/views/admin_data/feed/index.rss.builder +25 -0
- data/app/views/admin_data/home/index.html.erb +21 -0
- data/app/views/admin_data/migration/index.html.erb +18 -0
- data/app/views/admin_data/migration/jstest.html.erb +51 -0
- data/app/views/admin_data/search/advance_search.html.erb +1 -0
- data/app/views/admin_data/search/quick_search.html.erb +1 -0
- data/app/views/admin_data/search/search/_advance_search_form.html.erb +52 -0
- data/app/views/admin_data/search/search/_errors.html.erb +5 -0
- data/app/views/admin_data/search/search/_listing.html.erb +43 -0
- data/app/views/admin_data/search/search/_search_form.html.erb +27 -0
- data/app/views/admin_data/search/search/_title.html.erb +34 -0
- data/app/views/admin_data/shared/_breadcrum.html.erb +16 -0
- data/app/views/admin_data/shared/_drop_down_klasses.html.erb +4 -0
- data/app/views/admin_data/shared/_flash_message.html.erb +13 -0
- data/app/views/admin_data/shared/_header.html.erb +20 -0
- data/app/views/admin_data/shared/_powered_by.html.erb +6 -0
- data/app/views/admin_data/shared/_secondary_navigation.html.erb +26 -0
- data/app/views/admin_data/table_structure/index.html.erb +54 -0
- data/app/views/layouts/admin_data.html.erb +34 -0
- data/app/views/layouts/admin_data/application.html.erb +14 -0
- data/app/views/layouts/search.html.erb +71 -0
- data/config/routes.rb +32 -0
- data/lib/admin_data.rb +27 -0
- data/lib/admin_data/active_record_util.rb +102 -0
- data/lib/admin_data/analytics.rb +176 -0
- data/lib/admin_data/authenticator.rb +15 -0
- data/lib/admin_data/config.rb +38 -0
- data/lib/admin_data/configuration.rb +127 -0
- data/lib/admin_data/date_util.rb +58 -0
- data/lib/admin_data/engine.rb +17 -0
- data/lib/admin_data/model_finder.rb +15 -0
- data/lib/admin_data/rails_version_check.rb +8 -0
- data/lib/admin_data/search.rb +188 -0
- data/lib/admin_data/setup_config.rb +24 -0
- data/lib/admin_data/util.rb +102 -0
- data/lib/admin_data/version.rb +3 -0
- data/lib/tasks/admin_data_tasks.rake +4 -0
- data/script/rails +8 -0
- data/test/admin_data_test.rb +7 -0
- data/test/dummy/README.md +19 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +5 -0
- data/test/dummy/app/models/user.rb +3 -0
- data/test/dummy/app/models/user/student.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +15 -0
- data/test/dummy/config/boot.rb +13 -0
- data/test/dummy/config/cucumber.yml +9 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/database.yml.mysql +22 -0
- data/test/dummy/config/database.yml.pg +15 -0
- data/test/dummy/config/database.yml.sqlite3 +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +22 -0
- data/test/dummy/config/environments/production.rb +49 -0
- data/test/dummy/config/environments/test.rb +35 -0
- data/test/dummy/config/initializers/admin_data.rb +15 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/empty_spaces_to_nil.rb +10 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +9 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20091030202259_create_tables.rb +72 -0
- data/test/dummy/db/production.sqlite3 +1 -0
- data/test/dummy/db/schema.rb +23 -0
- data/test/dummy/db/seeds.rb +40 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/features/advance_search/boolean.feature +74 -0
- data/test/dummy/features/advance_search/datetime.feature +101 -0
- data/test/dummy/features/advance_search/delete_all.feature +20 -0
- data/test/dummy/features/advance_search/destroy_all.feature +20 -0
- data/test/dummy/features/advance_search/integer.feature +69 -0
- data/test/dummy/features/advance_search/multiple_rows.feature +87 -0
- data/test/dummy/features/advance_search/string.feature +130 -0
- data/test/dummy/features/crud.feature +50 -0
- data/test/dummy/features/crud_show.feature +56 -0
- data/test/dummy/features/feed.feature +13 -0
- data/test/dummy/features/home.feature +42 -0
- data/test/dummy/features/migration.feature +7 -0
- data/test/dummy/features/quick_search.feature +113 -0
- data/test/dummy/features/step_definitions/advance_search_steps.rb +13 -0
- data/test/dummy/features/step_definitions/app_steps.rb +36 -0
- data/test/dummy/features/step_definitions/async.rb +18 -0
- data/test/dummy/features/step_definitions/configuration_steps.rb +61 -0
- data/test/dummy/features/step_definitions/crud_show_steps.rb +37 -0
- data/test/dummy/features/step_definitions/feed_steps.rb +24 -0
- data/test/dummy/features/step_definitions/quick_search_steps.rb +68 -0
- data/test/dummy/features/step_definitions/util.rb +90 -0
- data/test/dummy/features/step_definitions/web_steps.rb +219 -0
- data/test/dummy/features/support/env.rb +66 -0
- data/test/dummy/features/support/hooks.rb +9 -0
- data/test/dummy/features/support/paths.rb +33 -0
- data/test/dummy/features/table_structure.feature +18 -0
- data/test/dummy/lib/tasks/.gitkeep +0 -0
- data/test/dummy/lib/tasks/cucumber.rake +53 -0
- data/test/dummy/lib/tasks/dbs.rake +30 -0
- data/test/dummy/lib/tasks/sample_cars.rake +18 -0
- data/test/dummy/public/.gitkeep +0 -0
- data/test/dummy/script/cucumber +10 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/test/factories.rb +30 -0
- data/test/dummy/test/test_helper.rb +7 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/test_helper.rb +15 -0
- data/test/unit/admin_data/model_finder_test.rb +16 -0
- data/test/unit/car_test.rb +96 -0
- data/test/unit/user_phone_test.rb +19 -0
- metadata +253 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
module AdminData
|
|
2
|
+
|
|
3
|
+
class CrudController < ApplicationController
|
|
4
|
+
|
|
5
|
+
before_filter :get_class_from_params, :only => [:show, :destroy, :del, :edit, :new, :update, :create]
|
|
6
|
+
|
|
7
|
+
before_filter :get_model_and_verify_it, :only => [:destroy, :del, :edit, :update, :show]
|
|
8
|
+
|
|
9
|
+
before_filter :ensure_is_allowed_to_update, :only => [:destroy, :del, :edit, :update, :create]
|
|
10
|
+
|
|
11
|
+
def show
|
|
12
|
+
@page_title = "#{@klass.name.underscore}:#{@model.id}"
|
|
13
|
+
respond_to {|format| format.html}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def destroy
|
|
17
|
+
@klass.send(:destroy, params[:id])
|
|
18
|
+
redirect_to admin_data_search_path(:klass => @klass.name.underscore)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def del
|
|
22
|
+
@klass.send(:delete, params[:id])
|
|
23
|
+
flash[:success] = 'Record was deleted'
|
|
24
|
+
redirect_to admin_data_search_path(:klass => @klass.name.underscore)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def edit
|
|
28
|
+
@page_title = "edit #{@klass.name.underscore}:#{@model.id}"
|
|
29
|
+
@columns = columns_list
|
|
30
|
+
respond_to {|format| format.html}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def new
|
|
34
|
+
@page_title = "new #{@klass.name.underscore}"
|
|
35
|
+
@model = @klass.send(:new)
|
|
36
|
+
@columns = columns_list
|
|
37
|
+
respond_to {|format| format.html}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def update
|
|
41
|
+
model_attrs = params[@klass.name.underscore]
|
|
42
|
+
@columns = columns_list
|
|
43
|
+
|
|
44
|
+
respond_to do |format|
|
|
45
|
+
if @model.update_attributes(model_attrs)
|
|
46
|
+
format.html do
|
|
47
|
+
flash[:success] = "Record was updated"
|
|
48
|
+
redirect_to admin_data_path(:id => @model.id, :klass => @klass.name.underscore)
|
|
49
|
+
end
|
|
50
|
+
format.js { render :json => {:success => true}}
|
|
51
|
+
else
|
|
52
|
+
format.html { render :action => 'edit' }
|
|
53
|
+
format.js { render :json => {:error => @model.errors.full_messages.join } }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def create
|
|
59
|
+
model_attrs = params[@klass.name.underscore]
|
|
60
|
+
@model = @klass.create(model_attrs)
|
|
61
|
+
@columns = columns_list
|
|
62
|
+
|
|
63
|
+
respond_to do |format|
|
|
64
|
+
if @model.errors.any?
|
|
65
|
+
format.html { render :action => 'new' }
|
|
66
|
+
format.js { render :json => {:error => @model.errors.full_messages.join() }}
|
|
67
|
+
else
|
|
68
|
+
format.html do
|
|
69
|
+
flash[:success] = "Record was created"
|
|
70
|
+
redirect_to admin_data_path(:id => @model.id, :klass => @klass.name.underscore)
|
|
71
|
+
end
|
|
72
|
+
format.js { render :json => {} }
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def get_model_and_verify_it
|
|
80
|
+
primary_key = @klass.primary_key.intern
|
|
81
|
+
conditional_id = params[:id] =~ /^(\d+)-.*/ ? params[:id].to_i : params[:id]
|
|
82
|
+
condition = {primary_key => conditional_id}
|
|
83
|
+
|
|
84
|
+
_proc = AdminData.config.find_conditions[@klass.name]
|
|
85
|
+
if _proc && (find_conditions = _proc.call(params)) && find_conditions.has_key?(:conditions)
|
|
86
|
+
condition = find_conditions.fetch(:conditions)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
unless @model = @klass.find(:first, :conditions => condition)
|
|
90
|
+
render :text => "#{@klass.name} not found: #{params[:id]}"
|
|
91
|
+
return
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def columns_list
|
|
96
|
+
params[:attr].blank? ? @klass.columns : @klass.columns.find_all {|col| params[:attr] == col.name}
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module AdminData
|
|
2
|
+
|
|
3
|
+
class FeedController < ApplicationController
|
|
4
|
+
|
|
5
|
+
before_filter :ensure_is_allowed_to_view_feed
|
|
6
|
+
|
|
7
|
+
def index
|
|
8
|
+
if params[:klasss].blank?
|
|
9
|
+
render :text => "Usage: http://localhost:3000/admin_data/feed/user replace user with your model name"
|
|
10
|
+
return
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
begin
|
|
14
|
+
@klass = Util.camelize_constantize(params[:klasss])
|
|
15
|
+
@title = "Feeds from admin_data #{@klass.name}"
|
|
16
|
+
@description = "feeds from AdminData #{@klass.name}"
|
|
17
|
+
@records = @klass.find(:all, :order => "#{@klass.primary_key} desc", :limit => 100)
|
|
18
|
+
rescue NameError
|
|
19
|
+
render :text => "No constant was found with name #{params[:klasss]}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def ensure_is_allowed_to_view_feed
|
|
26
|
+
render :text => 'not authorized' unless is_allowed_to_view_feed?(self)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def is_allowed_to_view_feed?(controller)
|
|
30
|
+
return true if Rails.env.development?
|
|
31
|
+
|
|
32
|
+
if AdminData.config.feed_authentication_user_id.blank?
|
|
33
|
+
Rails.logger.info 'No user id has been supplied for feed'
|
|
34
|
+
return false
|
|
35
|
+
elsif AdminData.config.feed_authentication_password.blank?
|
|
36
|
+
Rails.logger.info 'No password has been supplied for feed'
|
|
37
|
+
return false
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
userid = AdminData.config.feed_authentication_user_id
|
|
41
|
+
password = AdminData.config.feed_authentication_password
|
|
42
|
+
authenticator = AdminData::Authenticator.new(userid, password)
|
|
43
|
+
authenticator.verify(controller)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module AdminData
|
|
2
|
+
class MigrationController < ApplicationController
|
|
3
|
+
|
|
4
|
+
before_filter :ensure_is_allowed_to_view
|
|
5
|
+
|
|
6
|
+
def index
|
|
7
|
+
@page_title = 'migration information'
|
|
8
|
+
@data = ActiveRecord::Base.connection.select_all('select * from schema_migrations')
|
|
9
|
+
respond_to {|format| format.html}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def jstest
|
|
13
|
+
@page_title = 'jstest'
|
|
14
|
+
respond_to {|format| format.html { render :layout => false}}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module AdminData
|
|
2
|
+
class PublicController < ApplicationController
|
|
3
|
+
|
|
4
|
+
def serve
|
|
5
|
+
path = File.join(AdminData::LIBPATH, '..', 'app', 'assets', params[:file])
|
|
6
|
+
|
|
7
|
+
unless File.expand_path(path) =~ /admin_data/
|
|
8
|
+
render :nothing => true, :status => 404 and return
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
case params[:format].to_s.downcase
|
|
12
|
+
when 'css'
|
|
13
|
+
content_type = "text/css"
|
|
14
|
+
when 'js'
|
|
15
|
+
content_type = "text/javascript"
|
|
16
|
+
when 'png'
|
|
17
|
+
content_type = "image/png"
|
|
18
|
+
when 'jpg'
|
|
19
|
+
content_type = "image/jpg"
|
|
20
|
+
else
|
|
21
|
+
render :nothing => true, :status => 404 and return
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
render({:text => File.read("#{path}.#{params[:format]}"), :cache => true, :content_type => content_type})
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
class SearchAction
|
|
2
|
+
attr_accessor :relation, :success_message
|
|
3
|
+
|
|
4
|
+
def initialize(relation)
|
|
5
|
+
@relation = relation
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def delete
|
|
9
|
+
count = relation.count
|
|
10
|
+
relation.delete_all
|
|
11
|
+
self.success_message = "#{count} #{AdminData::Util.pluralize(count, 'record')} deleted"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def destroy
|
|
15
|
+
count = relation.count
|
|
16
|
+
relation.find_in_batches do |group|
|
|
17
|
+
group.each {|record| record.destroy }
|
|
18
|
+
end
|
|
19
|
+
self.success_message = "#{count} #{AdminData::Util.pluralize(count, 'record')} destroyed"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module AdminData
|
|
24
|
+
class SearchController < ApplicationController
|
|
25
|
+
|
|
26
|
+
layout 'search'
|
|
27
|
+
|
|
28
|
+
include AdminData::Search
|
|
29
|
+
|
|
30
|
+
before_filter :get_class_from_params
|
|
31
|
+
before_filter :ensure_valid_children_klass, :only => [:quick_search]
|
|
32
|
+
before_filter :ensure_is_authorized_for_update_opration, :only => [:advance_search]
|
|
33
|
+
before_filter :set_column_type_info, :only => [:advance_search]
|
|
34
|
+
before_filter :handle_sorting
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def quick_search
|
|
38
|
+
@page_title = "Search #{@klass.name.underscore}"
|
|
39
|
+
order = default_order
|
|
40
|
+
|
|
41
|
+
if params[:base]
|
|
42
|
+
klass = Util.camelize_constantize(params[:base])
|
|
43
|
+
model = klass.find(params[:model_id])
|
|
44
|
+
has_many_proxy = model.send(params[:children].intern)
|
|
45
|
+
@total_num_of_children = has_many_proxy.send(:count)
|
|
46
|
+
h = { :page => params[:page], :per_page => per_page, :order => order }
|
|
47
|
+
@records = has_many_proxy.send(:paginate, h)
|
|
48
|
+
else
|
|
49
|
+
params[:query] = params[:query].strip unless params[:query].blank?
|
|
50
|
+
cond = build_quick_search_condition(@klass, params[:query])
|
|
51
|
+
h = { :page => params[:page], :per_page => per_page, :order => order, :conditions => cond }
|
|
52
|
+
@records = @klass.unscoped.paginate(h)
|
|
53
|
+
end
|
|
54
|
+
respond_to {|format| format.html}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def advance_search
|
|
59
|
+
@page_title = "Advance search #{@klass.name.underscore}"
|
|
60
|
+
hash = build_advance_search_condition(@klass, params[:adv_search])
|
|
61
|
+
relation = hash[:cond]
|
|
62
|
+
errors = hash[:errors]
|
|
63
|
+
order = default_order
|
|
64
|
+
|
|
65
|
+
respond_to do |format|
|
|
66
|
+
format.html { render }
|
|
67
|
+
format.js {
|
|
68
|
+
|
|
69
|
+
unless hash[:errors].blank?
|
|
70
|
+
file = File.join(AdminData::LIBPATH, '..', 'app','views', 'admin_data', 'search', 'search', '_errors.html.erb')
|
|
71
|
+
render :file => file, :locals => {:errors => errors}
|
|
72
|
+
return
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
search_action = SearchAction.new(relation)
|
|
76
|
+
|
|
77
|
+
case params[:admin_data_advance_search_action_type]
|
|
78
|
+
when 'destroy'
|
|
79
|
+
search_action.destroy
|
|
80
|
+
when 'delete'
|
|
81
|
+
search_action.delete
|
|
82
|
+
else
|
|
83
|
+
@records = relation.order(order).paginate(:page => params[:page], :per_page => per_page)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
if search_action.success_message
|
|
87
|
+
render :json => {:success => search_action.success_message }
|
|
88
|
+
else
|
|
89
|
+
file = "/admin_data/search/search/listing.html.erb"
|
|
90
|
+
render :partial => file, :locals => {:klass => @klass}, :layout => false
|
|
91
|
+
end
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def ensure_valid_children_klass
|
|
99
|
+
if params[:base]
|
|
100
|
+
begin
|
|
101
|
+
model_klass = Util.camelize_constantize(params[:base])
|
|
102
|
+
rescue NameError => e #incase params[:base] is junk value
|
|
103
|
+
render :text => "#{params[:base]} is an invalid value", :status => :not_found
|
|
104
|
+
return
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
ar_util = ActiveRecordUtil.new(model_klass)
|
|
108
|
+
if ar_util.declared_has_many_association_names.include?(params[:children]) || ar_util.declared_habtm_association_names.include?(params[:children])
|
|
109
|
+
#proceed
|
|
110
|
+
else
|
|
111
|
+
render :text => "#{params[:children]} is not a valid has_many association", :status => :not_found
|
|
112
|
+
return
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def ensure_is_authorized_for_update_opration
|
|
118
|
+
if %w(destroy delete).include? params[:admin_data_advance_search_action_type]
|
|
119
|
+
render :text => 'not authorized' unless is_allowed_to_update?
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def default_order
|
|
124
|
+
params[:sortby] || "#{@klass.send(:table_name)}.#{@klass.send(:primary_key)} desc"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def set_column_type_info
|
|
128
|
+
column_type_info = @klass.columns.collect { |column|
|
|
129
|
+
#JSLint complains if a hash has key named boolean. So I am changing the key to booleant
|
|
130
|
+
column_type = (column.type.to_s == 'boolean') ? 'booleant' : column.type.to_s
|
|
131
|
+
%Q{ "#{column.name}":"#{column_type}" }
|
|
132
|
+
}.join(',')
|
|
133
|
+
@column_type_info = "{#{column_type_info}}"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def handle_sorting
|
|
137
|
+
sort_order = params[:sortby] || 'id desc'
|
|
138
|
+
@sort_by_column_name, @sort_order = sort_order.split
|
|
139
|
+
@sort_css = @sort_order == 'asc' ? 'sort_by_asc' : 'sort_by_desc'
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
end
|
|
143
|
+
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,320 @@
|
|
|
1
|
+
module AdminData
|
|
2
|
+
module ApplicationHelper
|
|
3
|
+
|
|
4
|
+
def get_sort_order(column)
|
|
5
|
+
if column == @sort_by_column_name && @sort_order == 'desc'
|
|
6
|
+
"#{column} asc"
|
|
7
|
+
else
|
|
8
|
+
"#{column} desc"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def get_sort_title_with_url(column, klass)
|
|
13
|
+
order = get_sort_order(column)
|
|
14
|
+
link_to column_title(klass, column), search_path(:klass => klass, :query => params[:query], :sortby => order)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def get_sort_class(column)
|
|
18
|
+
sort_class = 'sortable'
|
|
19
|
+
if column == @sort_by_column_name
|
|
20
|
+
sort_class << ' ' + @sort_css
|
|
21
|
+
end
|
|
22
|
+
sort_class
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def parent_layout(layout)
|
|
26
|
+
content_for(:layout, self.output_buffer)
|
|
27
|
+
self.output_buffer = render(:file => "layouts/#{layout}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def column_title(klass, column)
|
|
31
|
+
AdminData.config.column_headers[klass.name].try(:fetch,column.intern, nil) || column
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# AdminData.config.columns_order might not list all the columns of a given table. However
|
|
35
|
+
# the listed columns should be at the front in the order mentioned. Primary key will also
|
|
36
|
+
# be the first column. Consumer might define a new column name that is not listed a column.
|
|
37
|
+
#
|
|
38
|
+
def columns_order(klass)
|
|
39
|
+
columns_symbol = klass.columns.map {|e| e.name.intern}
|
|
40
|
+
|
|
41
|
+
# created_at and updated_at should be at the very end by default
|
|
42
|
+
if columns_symbol.include? :created_at
|
|
43
|
+
columns_symbol = (columns_symbol - [:created_at]) + [:created_at]
|
|
44
|
+
end
|
|
45
|
+
if columns_symbol.include? :updated_at
|
|
46
|
+
columns_symbol = (columns_symbol - [:updated_at]) + [:updated_at]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
if requested_order = AdminData.config.columns_order[klass.name]
|
|
50
|
+
primary_key = klass.send(:primary_key).intern
|
|
51
|
+
order = [primary_key] + requested_order
|
|
52
|
+
order.uniq!
|
|
53
|
+
# add the columns not covered by user at the end of the list
|
|
54
|
+
sorted_columns = order + (columns_symbol - order)
|
|
55
|
+
sorted_columns.map(&:to_s)
|
|
56
|
+
else
|
|
57
|
+
columns_symbol.map(&:to_s)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def total_records_info(klass)
|
|
62
|
+
'(Total ' + pluralize(klass.count, 'record') + ' )'
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def search_result_title(total_num_of_children, records)
|
|
66
|
+
output = []
|
|
67
|
+
if params[:base]
|
|
68
|
+
label = params[:base].camelize + ' ID ' + params[:model_id]
|
|
69
|
+
output << link_to(label, admin_data_path(:klass => params[:base], :id => params[:model_id]))
|
|
70
|
+
output << 'has'
|
|
71
|
+
output << pluralize(total_num_of_children, params[:klass])
|
|
72
|
+
|
|
73
|
+
elsif !params[:query].blank? || params[:adv_search]
|
|
74
|
+
output << 'Search result:'
|
|
75
|
+
output << pluralize(records.total_entries, 'record')
|
|
76
|
+
output << 'found'
|
|
77
|
+
|
|
78
|
+
else
|
|
79
|
+
output << 'All '
|
|
80
|
+
output << params[:klass].camelize
|
|
81
|
+
output << 'records'
|
|
82
|
+
end
|
|
83
|
+
output.join(' ').html_safe
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def column_native(klass, column)
|
|
87
|
+
klass.send(:columns).select {|r| r.instance_variable_get('@name') == column}.first || column
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def has_one(model, klass)
|
|
91
|
+
tmp = ActiveRecordUtil.new(klass).declared_has_one_association_names
|
|
92
|
+
tmp.inject('') do |output, ho|
|
|
93
|
+
begin
|
|
94
|
+
label = ho
|
|
95
|
+
if model.send(ho)
|
|
96
|
+
output << link_to(label, admin_data_path(:klass => ho.underscore, :id => model.send(ho)))
|
|
97
|
+
else
|
|
98
|
+
output << label
|
|
99
|
+
end
|
|
100
|
+
rescue => e
|
|
101
|
+
Rails.logger.debug Util.exception_info(e)
|
|
102
|
+
end
|
|
103
|
+
output
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def has_many_data(model, klass)
|
|
108
|
+
array = ActiveRecordUtil.new(klass).declared_has_many_association_names.map do |m|
|
|
109
|
+
begin
|
|
110
|
+
count = model.send(m.intern).count
|
|
111
|
+
label = m.to_s + '(' + count.to_s + ')'
|
|
112
|
+
output = label
|
|
113
|
+
if count > 0
|
|
114
|
+
has_many_klass_name = ActiveRecordUtil.new(model.class).klass_for_association_type_and_name(:has_many, m).name.underscore
|
|
115
|
+
output = link_to(label, search_path( :klass => has_many_klass_name,
|
|
116
|
+
:children => m,
|
|
117
|
+
:base => klass.name.underscore,
|
|
118
|
+
:model_id => model.id))
|
|
119
|
+
end
|
|
120
|
+
rescue => e
|
|
121
|
+
Rails.logger.debug Util.exception_info(e)
|
|
122
|
+
end
|
|
123
|
+
output
|
|
124
|
+
end
|
|
125
|
+
array.join(', ')
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def belongs_to_data(model, klass)
|
|
129
|
+
ActiveRecordUtil.new(klass).declared_belongs_to_association_names.map do |assoc_name|
|
|
130
|
+
begin
|
|
131
|
+
output = assoc_name
|
|
132
|
+
if belongs_to_record = model.send(assoc_name)
|
|
133
|
+
output = link_to(assoc_name, admin_data_path(:klass => belongs_to_record.class.name.underscore, :id => belongs_to_record.id))
|
|
134
|
+
end
|
|
135
|
+
rescue => e
|
|
136
|
+
Rails.logger.info Util.exception_info(e)
|
|
137
|
+
end
|
|
138
|
+
output
|
|
139
|
+
end.join(', ')
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def habtm_data(model, klass)
|
|
143
|
+
ActiveRecordUtil.new(klass).declared_habtm_association_names.map do |assoc_name|
|
|
144
|
+
begin
|
|
145
|
+
count = model.send(assoc_name.intern).count
|
|
146
|
+
label = assoc_name + '(' + count.to_s + ')'
|
|
147
|
+
output = label
|
|
148
|
+
|
|
149
|
+
if count > 0 then
|
|
150
|
+
has_many_klass_name = ActiveRecordUtil.new(model.class).klass_for_association_type_and_name(:has_and_belongs_to_many, assoc_name).name.underscore
|
|
151
|
+
output = link_to(label, search_path( :klass => has_many_klass_name,
|
|
152
|
+
:children => assoc_name,
|
|
153
|
+
:base => klass.name.underscore,
|
|
154
|
+
:model_id => model.id))
|
|
155
|
+
end
|
|
156
|
+
rescue => e
|
|
157
|
+
Rails.logger.info Util.exception_info(e)
|
|
158
|
+
end
|
|
159
|
+
output
|
|
160
|
+
end.join(', ')
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def breadcrum(&block)
|
|
164
|
+
render(:partial => '/admin_data/shared/breadcrum', :locals => {:data => capture(&block)})
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def form_field(klass, model, col, f)
|
|
168
|
+
html = []
|
|
169
|
+
column_value = model.send(col.name)
|
|
170
|
+
|
|
171
|
+
if klass.serialized_attributes.has_key?(col.name)
|
|
172
|
+
return Util.get_serialized_value(html,column_value)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
if col.primary
|
|
176
|
+
html << model.new_record? ? '(auto)' : model.id
|
|
177
|
+
elsif get_reflection_for_column(klass, col) && AdminData.config.display_assoc?( klass.name )
|
|
178
|
+
form_field_for_association_records(klass, col, f, html)
|
|
179
|
+
else
|
|
180
|
+
handle_column_type(col, html, model, column_value, f)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def form_field_for_association_records(klass, col, f, html)
|
|
186
|
+
begin
|
|
187
|
+
reflection = get_reflection_for_column(klass, col)
|
|
188
|
+
|
|
189
|
+
# in some edge cases following code throws exception. investigating ..
|
|
190
|
+
options = reflection.options
|
|
191
|
+
if options.keys.include?(:polymorphic) && options.fetch(:polymorphic)
|
|
192
|
+
build_text_field(html, f, col)
|
|
193
|
+
else
|
|
194
|
+
ref_klass = reflection.klass
|
|
195
|
+
association_name = ref_klass.columns.map(&:name).include?('name') ? :name : ref_klass.primary_key
|
|
196
|
+
all_for_dropdown = ref_klass.all(:order => "#{association_name} asc")
|
|
197
|
+
html << f.collection_select(col.name, all_for_dropdown, :id, association_name, :include_blank => true)
|
|
198
|
+
end
|
|
199
|
+
html.join
|
|
200
|
+
rescue Exception => e
|
|
201
|
+
Rails.logger.info Util.exception_info(e)
|
|
202
|
+
'could not retrieve' # returning nil
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def form_field_for_habtm_records(klass, model, f, html)
|
|
207
|
+
begin
|
|
208
|
+
html = []
|
|
209
|
+
ActiveRecordUtil.new(klass).delcared_habtm_association_names.each do |k|
|
|
210
|
+
assoc_klass = Util.get_class_name_for_habtm_association(model, k)
|
|
211
|
+
|
|
212
|
+
html << "<div class='col_box'>"
|
|
213
|
+
html << " <span class='col_name'>#{assoc_klass.table_name}</span>"
|
|
214
|
+
html << " <span class='col_type'>[integer]</span>"
|
|
215
|
+
html << "</div>"
|
|
216
|
+
|
|
217
|
+
order_by = assoc_klass.columns.map(&:name).include?('name') ? :name : assoc_klass.primary_key
|
|
218
|
+
all = assoc_klass.all(:order => order_by)
|
|
219
|
+
selected = model.send(assoc_klass.table_name).map{|e| e.id}
|
|
220
|
+
html << f.collection_select(assoc_klass.table_name, all, :id, order_by,
|
|
221
|
+
{:include_blank => false, :selected => selected},
|
|
222
|
+
{:multiple => true, :size => (all.count > 10 ? 8 : 4)})
|
|
223
|
+
end
|
|
224
|
+
html.join
|
|
225
|
+
rescue Exception => e
|
|
226
|
+
Rails.logger.info Util.exception_info(e)
|
|
227
|
+
'could not retrieve' # returning nil
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def handle_column_type(col, html, model, column_value, f)
|
|
232
|
+
case col.type
|
|
233
|
+
when :text
|
|
234
|
+
html << f.text_area(col.name, :rows => 6, :cols => 70)
|
|
235
|
+
|
|
236
|
+
when :datetime
|
|
237
|
+
if ['created_at', 'updated_at'].include?(col.name)
|
|
238
|
+
html << '(auto)'
|
|
239
|
+
else
|
|
240
|
+
value = params[:action] == 'new' ? Time.now : column_value
|
|
241
|
+
year_value = value.year if value
|
|
242
|
+
datetime_selects = f.datetime_select(col.name, :include_blank => true)
|
|
243
|
+
html << datetime_selects.gsub('type="hidden"', 'type="text" size="4" class="nice-field"')
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
when :date
|
|
247
|
+
value = params[:action] == 'new' ? Time.now : column_value
|
|
248
|
+
year_value = value.year if value
|
|
249
|
+
date_selects = f.date_select(col.name, :discard_year => true, :include_blank => true)
|
|
250
|
+
html << date_selects.gsub('type="hidden"', 'type="text" size="4" class="nice-field"')
|
|
251
|
+
|
|
252
|
+
when :time
|
|
253
|
+
# time_select method of rails is buggy and is causing problem
|
|
254
|
+
# 1 error(s) on assignment of multiparameter attributes
|
|
255
|
+
#
|
|
256
|
+
# will try again this method with Rails 3
|
|
257
|
+
#html << f.time_select(col.name, :include_blank => true, :include_seconds => true)
|
|
258
|
+
|
|
259
|
+
when :boolean
|
|
260
|
+
html << f.select(col.name, [['True', true], ['False', false]], :include_blank => true)
|
|
261
|
+
|
|
262
|
+
else
|
|
263
|
+
build_text_field(html, f, col)
|
|
264
|
+
end
|
|
265
|
+
html.join
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def build_text_field(html, f, col)
|
|
270
|
+
options = {:class => 'nice-field'}
|
|
271
|
+
if AdminData.config.ignore_column_limit
|
|
272
|
+
options[:size] = 60
|
|
273
|
+
options[:maxlength] = 255
|
|
274
|
+
else
|
|
275
|
+
options[:size] = (col && col.limit && col.limit < 60) ? col.limit : 60
|
|
276
|
+
options[:maxlength] = col.limit if col.limit
|
|
277
|
+
end
|
|
278
|
+
html << f.text_field(col.name, options)
|
|
279
|
+
html.join
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# uses truncate method
|
|
283
|
+
# options supports :limit which is applied if the column type is string or text.
|
|
284
|
+
# calls the inspect method to convert to a string if the column is serialized.
|
|
285
|
+
# TODO rspec test limit option
|
|
286
|
+
def get_value_for_column(column, model, options = {})
|
|
287
|
+
options.reverse_merge!(:limit => 400)
|
|
288
|
+
|
|
289
|
+
value = Util.custom_value_for_column(column, model)
|
|
290
|
+
|
|
291
|
+
if column.is_a?(String)
|
|
292
|
+
value
|
|
293
|
+
elsif column.type == :datetime
|
|
294
|
+
value.strftime('%d-%B-%Y %H:%M:%S %p') unless value.blank?
|
|
295
|
+
elsif column.type == :string || column.type == :text
|
|
296
|
+
value = value.inspect if model.class.serialized_attributes.keys.include?(column.name)
|
|
297
|
+
return value if options[:limit].blank?
|
|
298
|
+
begin
|
|
299
|
+
truncate(value,:length => options[:limit])
|
|
300
|
+
rescue # truncate method failed
|
|
301
|
+
'<actual data is not being shown because truncate method failed.>'
|
|
302
|
+
end
|
|
303
|
+
else
|
|
304
|
+
value.to_s
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def get_reflection_for_column(klass, col)
|
|
309
|
+
klass.reflections.values.detect { |reflection| reflection.foreign_key.to_sym == col.name.to_sym }
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def record_id(record)
|
|
313
|
+
if record.respond_to?(:primary_key)
|
|
314
|
+
record.send(:primary_key)
|
|
315
|
+
else
|
|
316
|
+
record.id
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|