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