introspective_admin 0.1.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/.travis.yml +5 -14
  4. data/CHANGELOG.md +37 -28
  5. data/Gemfile +15 -6
  6. data/Gemfile.lock +347 -264
  7. data/README.md +34 -8
  8. data/introspective_admin.gemspec +34 -44
  9. data/lib/introspective_admin/base.rb +200 -200
  10. data/lib/introspective_admin/version.rb +3 -3
  11. data/spec/admin/company_admin_spec.rb +72 -72
  12. data/spec/admin/job_admin_spec.rb +61 -61
  13. data/spec/admin/location_admin_spec.rb +66 -66
  14. data/spec/admin/location_beacon_admin_spec.rb +73 -73
  15. data/spec/admin/project__admin_spec.rb +71 -71
  16. data/spec/admin/user_admin_spec.rb +64 -64
  17. data/spec/dummy/Gemfile +15 -0
  18. data/spec/dummy/README.rdoc +28 -28
  19. data/spec/dummy/Rakefile +6 -6
  20. data/spec/dummy/app/admin/admin_users.rb +28 -0
  21. data/spec/dummy/app/admin/company_admin.rb +4 -4
  22. data/spec/dummy/app/admin/dashboard.rb +32 -0
  23. data/spec/dummy/app/admin/job_admin.rb +4 -4
  24. data/spec/dummy/app/admin/location_admin.rb +4 -4
  25. data/spec/dummy/app/admin/location_beacon_admin.rb +6 -6
  26. data/spec/dummy/app/admin/project_admin.rb +6 -6
  27. data/spec/dummy/app/admin/role_admin.rb +5 -5
  28. data/spec/dummy/app/admin/user_admin.rb +13 -13
  29. data/spec/dummy/app/assets/config/manifest.js +3 -0
  30. data/spec/dummy/app/assets/javascripts/active_admin.js +1 -0
  31. data/spec/dummy/app/assets/javascripts/application.js +13 -13
  32. data/spec/dummy/app/assets/stylesheets/active_admin.scss +17 -0
  33. data/spec/dummy/app/assets/stylesheets/application.css +15 -15
  34. data/spec/dummy/app/controllers/application_controller.rb +8 -8
  35. data/spec/dummy/app/helpers/application_helper.rb +3 -3
  36. data/spec/dummy/app/models/abstract_adapter.rb +18 -12
  37. data/spec/dummy/app/models/admin_user.rb +10 -6
  38. data/spec/dummy/app/models/company.rb +12 -12
  39. data/spec/dummy/app/models/job.rb +10 -10
  40. data/spec/dummy/app/models/locatable.rb +6 -6
  41. data/spec/dummy/app/models/location.rb +26 -26
  42. data/spec/dummy/app/models/location_beacon.rb +19 -19
  43. data/spec/dummy/app/models/location_gps.rb +11 -11
  44. data/spec/dummy/app/models/project.rb +20 -20
  45. data/spec/dummy/app/models/project_job.rb +7 -7
  46. data/spec/dummy/app/models/role.rb +25 -25
  47. data/spec/dummy/app/models/team.rb +9 -9
  48. data/spec/dummy/app/models/team_user.rb +13 -13
  49. data/spec/dummy/app/models/user.rb +68 -68
  50. data/spec/dummy/app/models/user_location.rb +28 -28
  51. data/spec/dummy/app/models/user_project_job.rb +16 -16
  52. data/spec/dummy/app/views/layouts/application.html.erb +13 -13
  53. data/spec/dummy/bin/bundle +3 -3
  54. data/spec/dummy/bin/rails +4 -4
  55. data/spec/dummy/bin/rake +4 -4
  56. data/spec/dummy/bin/setup +29 -29
  57. data/spec/dummy/config/application.rb +34 -34
  58. data/spec/dummy/config/boot.rb +5 -5
  59. data/spec/dummy/config/database.yml +22 -22
  60. data/spec/dummy/config/environment.rb +11 -11
  61. data/spec/dummy/config/environments/development.rb +45 -45
  62. data/spec/dummy/config/environments/production.rb +82 -82
  63. data/spec/dummy/config/environments/test.rb +50 -50
  64. data/spec/dummy/config/initializers/active_admin.rb +7 -7
  65. data/spec/dummy/config/initializers/assets.rb +13 -13
  66. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -7
  67. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -3
  68. data/spec/dummy/config/initializers/devise.rb +263 -263
  69. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -4
  70. data/spec/dummy/config/initializers/inflections.rb +16 -16
  71. data/spec/dummy/config/initializers/mime_types.rb +4 -4
  72. data/spec/dummy/config/initializers/session_store.rb +3 -3
  73. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -14
  74. data/spec/dummy/config/initializers/zeitwerk.rb +8 -0
  75. data/spec/dummy/config/locales/devise.en.yml +60 -60
  76. data/spec/dummy/config/locales/en.yml +23 -23
  77. data/spec/dummy/config/routes.rb +10 -9
  78. data/spec/dummy/config/secrets.yml +20 -20
  79. data/spec/dummy/config.ru +4 -4
  80. data/spec/dummy/db/development.sqlite3 +0 -0
  81. data/spec/dummy/db/development.sqlite3-shm +0 -0
  82. data/spec/dummy/db/development.sqlite3-wal +0 -0
  83. data/spec/dummy/db/migrate/20141002205024_devise_create_users.rb +42 -42
  84. data/spec/dummy/db/migrate/20141002211055_devise_create_admin_users.rb +48 -48
  85. data/spec/dummy/db/migrate/20141002211057_create_active_admin_comments.rb +19 -19
  86. data/spec/dummy/db/migrate/20141002220722_add_lockable_to_users.rb +8 -8
  87. data/spec/dummy/db/migrate/20150406213646_create_companies.rb +11 -11
  88. data/spec/dummy/db/migrate/20150414213154_add_user_authentication_token.rb +11 -11
  89. data/spec/dummy/db/migrate/20150415222005_create_roles.rb +12 -12
  90. data/spec/dummy/db/migrate/20150505181635_create_chats.rb +9 -9
  91. data/spec/dummy/db/migrate/20150505181636_create_chat_users.rb +11 -11
  92. data/spec/dummy/db/migrate/20150505181640_create_chat_messages.rb +11 -11
  93. data/spec/dummy/db/migrate/20150507191529_create_chat_message_users.rb +11 -11
  94. data/spec/dummy/db/migrate/20150601200526_create_locations.rb +13 -13
  95. data/spec/dummy/db/migrate/20150601200533_create_locatables.rb +10 -10
  96. data/spec/dummy/db/migrate/20150601212924_create_location_beacons.rb +16 -16
  97. data/spec/dummy/db/migrate/20150601213542_create_location_gps.rb +12 -12
  98. data/spec/dummy/db/migrate/20150609201823_create_user_locations.rb +14 -14
  99. data/spec/dummy/db/migrate/20150617232519_create_projects.rb +10 -10
  100. data/spec/dummy/db/migrate/20150617232521_create_jobs.rb +9 -9
  101. data/spec/dummy/db/migrate/20150617232522_create_project_jobs.rb +11 -11
  102. data/spec/dummy/db/migrate/20150623170133_create_user_project_jobs.rb +12 -12
  103. data/spec/dummy/db/migrate/20150701234929_create_teams.rb +11 -11
  104. data/spec/dummy/db/migrate/20150701234930_create_team_users.rb +11 -11
  105. data/spec/dummy/db/migrate/20150727214950_add_confirmable_to_devise.rb +11 -11
  106. data/spec/dummy/db/migrate/20150820190524_add_user_names.rb +6 -6
  107. data/spec/dummy/db/migrate/20150909225019_add_password_to_project.rb +5 -5
  108. data/spec/dummy/db/migrate/20220806003731_add_devise_to_admin_users.rb +51 -0
  109. data/spec/dummy/db/schema.rb +264 -264
  110. data/spec/dummy/introspective_admin.gemspec +34 -0
  111. data/spec/dummy/public/404.html +67 -67
  112. data/spec/dummy/public/422.html +67 -67
  113. data/spec/dummy/public/500.html +66 -66
  114. data/spec/rails_helper.rb +27 -27
  115. metadata +25 -116
  116. data/Gemfile.lock.rails4 +0 -256
data/README.md CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  IntrospectiveAdmin is a Rails Plugin for DRYing up ActiveAdmin configurations by
20
20
  laying out simple defaults and including nested relations according to the models'
21
- accepts_nested_attributes_for :relation declarations.
21
+ accepts_nested_attributes_for :relation declarations.
22
22
 
23
23
  ## Documentation
24
24
 
@@ -28,7 +28,9 @@ In your Gemfile:
28
28
  gem 'introspective_admin'
29
29
  ```
30
30
 
31
- And bundle install. In app/admin/my_admin.rb:
31
+ And bundle install.
32
+
33
+ In app/admin/my_admin.rb:
32
34
 
33
35
  ```
34
36
  class MyAdmin < IntrospectiveAdmin::Base
@@ -39,7 +41,7 @@ class MyAdmin < IntrospectiveAdmin::Base
39
41
  def self.exclude_params
40
42
  %w(fields to exclude from the admin screen)
41
43
  end
42
-
44
+
43
45
  register MyModel do
44
46
  # It yields the ActiveAdmin DSL context back, allowing further configuration to
45
47
  # be added here, just as you would normally, to the Admin::MyModelController
@@ -48,29 +50,32 @@ class MyAdmin < IntrospectiveAdmin::Base
48
50
  end
49
51
  ```
50
52
 
51
- Registering MyModel will set up the index, show, and form configurations for every attribute, virtual attribute listed in MyAdmin.include_virtual_attributes (e.g. a password field for a Devise model), and nested association on the model excluding those in MyAdmin.exclude_params. It will link to associated records (if they have ActiveAdmin screens), perform eager loading of nested associations, and permit parameters for every non-excluded attribute on the model.
53
+ Registering MyModel will set up the index, show, and form configurations for every attribute, virtual attribute listed in MyAdmin.include_virtual_attributes (e.g. a password field for a Devise model), and nested association on the model excluding those in MyAdmin.exclude_params. It will link to associated records (if they have ActiveAdmin screens), perform eager loading of nested associations, and permit parameters for every non-excluded attribute on the model.
52
54
 
53
- Customizing select box options for associations is done by adding an
55
+ Customizing select box options for associations is done by adding an
54
56
  "options_for_X" class method on the administrated model:
55
57
 
56
58
  ```
59
+ app/models/my_model.rb
57
60
  class MyModel < ActiveRecord::Base
58
61
  belongs_to :parent
59
62
  has_many :other_models
60
63
  accepts_nested_attributes_for :other_models, :allow_destroy => true
61
64
 
62
65
  def self.options_for_parent(instance_of_my_model)
63
- Parent.order(:appelation).map.{|p| ["#{p.appelation}", p.id] }
66
+ Parent.order(:appelation).map.{|p| ["#{p.appelation}", p.id] }
64
67
  end
65
68
  end
66
69
  ```
67
70
 
68
71
  IntrospectiveAdmin will detect nested polymorphic relations and attempt to handle
69
- them using virutal attributes that you must add to the model instance, plus a class
72
+ them using virutal attributes that you must add to the model instance, plus a class
70
73
  method for the select box options, using a shared delimiter string for the compound ID.
71
- E.g. here we use a hyphen:
74
+
75
+ E.g. here we use a hyphen:
72
76
 
73
77
  ```
78
+ app/models/my_model.rb
74
79
  class MyModel < ActiveRecord::Base
75
80
  belongs_to :poly_model, polymorphic: true
76
81
  accepts_nested_attributes_for :poly_model, :allow_destroy => true
@@ -90,6 +95,27 @@ class MyModel < ActiveRecord::Base
90
95
  end
91
96
  ```
92
97
 
98
+ ActiveAdmin relies on [Ransack](https://github.com/activerecord-hackery/ransack) to power its searches. You will need
99
+ to explicitly declare attributes and associations to be accessible to ActiveAdmin. You can defeat the purpose by declaring everything accessible via your models' abstract base class, but be sure to exclude sensitive data:
100
+
101
+ ```
102
+ app/models/application_record.rb
103
+ def ApplicationRecord < ActiveRecord::Base
104
+ self.abstract_class = true
105
+
106
+ class << self
107
+ def ransackable_attributes(auth_object = nil)
108
+ @ransackable_attributes ||= column_names + _ransackers.keys - %w(password)
109
+ end
110
+
111
+ def ransackable_associations(auth_object = nil)
112
+ @ransackable_associations ||= reflect_on_all_associations.map { |a| a.name.to_s } + _ransackers.keys
113
+ end
114
+ end
115
+ end
116
+ ```
117
+
118
+
93
119
  ## Dependencies
94
120
 
95
121
  Tool | Description
@@ -1,44 +1,34 @@
1
- $:.push File.expand_path("../lib", __FILE__)
2
-
3
- # Maintain your gem's version:
4
- require "introspective_admin/version"
5
- require "introspective_admin/base"
6
-
7
- # Describe your gem and declare its dependencies:
8
- Gem::Specification.new do |s|
9
- s.name = "introspective_admin"
10
- s.version = IntrospectiveAdmin::VERSION
11
- s.authors = ["Josh Buermann"]
12
- s.email = ["buermann@gmail.com"]
13
- s.homepage = "https://github.com/buermann/introspective_admin"
14
- s.summary = "Set up basic ActiveAdmin screens for an ActiveRecord model."
15
- s.description = "Set up basic ActiveAdmin screens for an ActiveRecord model."
16
- s.license = "MIT"
17
-
18
- s.files = `git ls-files`.split("\n").sort
19
- s.test_files = `git ls-files -- spec/*`.split("\n")
20
-
21
- s.required_ruby_version = '>= 1.9.3'
22
-
23
- s.add_dependency 'rails'
24
- s.add_dependency 'activeadmin'
25
- s.add_dependency 'sass-rails'
26
- s.add_dependency 'sass'
27
-
28
-
29
- if RUBY_PLATFORM == 'java'
30
- s.add_development_dependency "activerecord-jdbcsqlite3-adapter"
31
- else
32
- s.add_development_dependency "sqlite3", '~> 1.3.6'
33
- end
34
- s.add_development_dependency "rspec-rails"
35
- s.add_development_dependency 'devise'
36
- s.add_development_dependency 'devise-async'
37
- s.add_development_dependency 'machinist_redux'
38
- s.add_development_dependency 'simplecov'
39
- s.add_development_dependency 'rufus-mnemo'
40
- s.add_development_dependency 'rails-controller-testing'
41
- s.add_development_dependency 'sprockets-rails'
42
-
43
- end
44
-
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ # Maintain your gem's version:
4
+ require "introspective_admin/version"
5
+ require "introspective_admin/base"
6
+
7
+ # Describe your gem and declare its dependencies:
8
+ Gem::Specification.new do |s|
9
+ s.name = "introspective_admin"
10
+ s.version = IntrospectiveAdmin::VERSION
11
+ s.authors = ["Josh Buermann"]
12
+ s.email = ["buermann@gmail.com"]
13
+ s.homepage = "https://github.com/buermann/introspective_admin"
14
+ s.summary = "Set up basic ActiveAdmin screens for an ActiveRecord model."
15
+ s.description = "Set up basic ActiveAdmin screens for an ActiveRecord model."
16
+ s.license = "MIT"
17
+
18
+ s.files = `git ls-files`.split("\n").sort
19
+ s.test_files = `git ls-files -- spec/*`.split("\n")
20
+
21
+ s.required_ruby_version = '>= 2.7.0'
22
+
23
+ s.add_dependency 'rails'
24
+ s.add_dependency 'activeadmin'
25
+ s.add_dependency 'sass-rails'
26
+ s.add_dependency 'sass'
27
+
28
+ if RUBY_PLATFORM == 'java'
29
+ s.add_development_dependency "activerecord-jdbcsqlite3-adapter"
30
+ else
31
+ s.add_development_dependency "sqlite3"
32
+ end
33
+ end
34
+
@@ -1,200 +1,200 @@
1
- module IntrospectiveAdmin
2
- class Base
3
- # Generate an active admin interface by introspecting on the models.
4
-
5
- # For polymorphic associations set up virtual 'assign' attributes on the model like so:
6
- #
7
- # def <polymorphism>_assign
8
- # "#{<polymorphism>_type}-#{<polymorphism>_id}"
9
- # end
10
- # def <polymorphism>_assign=(value)
11
- # self.<polymorphism>_type,self.<polymorphism>_id = value.split('-')
12
- # end
13
- #
14
- # And designate the selection options in a class method, you can pass the
15
- # target model to modify the options list accordingly
16
- #
17
- # def self.<polymorphism>_options(model=nil)
18
- # (Model.all + SecondModel.all).map { |i| [ i.name, "#{i.class}-#{i.id}"] }
19
- # end
20
-
21
- class << self
22
-
23
- def exclude_params
24
- [] # do not display the field in the index page and forms.
25
- end
26
-
27
- def include_virtual_attributes
28
- [] #
29
- end
30
-
31
- def polymorphic?(model,column)
32
- (model.reflections[column.sub(/_id$/,'')].try(:options)||{})[:polymorphic]
33
- end
34
-
35
- def column_list(model, extras=[])
36
- model.columns.map {|c|
37
- ref_name = c.name.sub(/(_type|_id)$/,'')
38
- model.reflections[ref_name] ? ref_name : c.name
39
- }.uniq-['created_at','updated_at']-exclude_params+extras
40
- end
41
-
42
- def params_list(model, extras=[])
43
- model.columns.map {|c|
44
- polymorphic?(model,c.name) ? c.name.sub(/_id$/,'')+"_assign" : c.name
45
- }+extras
46
- end
47
-
48
- def link_record(dsl, record)
49
- link_text = record.try(:name) || record.try(:title) || record.class.to_s
50
- link_href = begin dsl.send("admin_#{record.class.name.underscore}_path", record.id) rescue false end
51
- if link_href
52
- dsl.link_to link_text, link_href
53
- elsif link_text
54
- link_text
55
- else
56
- record
57
- end
58
- end
59
-
60
- def register(model, &block)
61
- # Defining activeadmin pages will break pending migrations:
62
- begin ActiveRecord::Migration.check_pending! rescue return end
63
-
64
- klass = self
65
- model_name = model.to_s.underscore
66
- nested_config = Hash[model.nested_attributes_options.reject {|name,o|
67
- klass.exclude_params.include?("#{name}_attributes")
68
- }.map {|assoc,options|
69
- reflection = model.reflections[assoc.to_s]
70
- reflection_class = reflection.class_name.constantize
71
- # merge the options of the nested attribute and relationship declarations
72
- options = options.merge(reflection_class.reflections[assoc.to_s].try(:options) || {})
73
- options[:class] = reflection_class
74
- options[:columns] = klass.column_list(reflection_class)
75
- options[:params] = klass.params_list(reflection_class)
76
- options[:reflection] = reflection
77
- options[:polymorphic_reference] = reflection.options[:as].to_s
78
- [assoc, options]
79
- }]
80
-
81
- ActiveAdmin.register model do
82
- instance_eval &block if block_given? # Evalutate the passed black for overrides to the defaults
83
-
84
- controller do
85
- def scoped_collection
86
- super.includes super.nested_attributes_options.keys
87
- end
88
- end
89
-
90
- index do
91
- selectable_column
92
- cols = model.columns.map(&:name)-klass.exclude_params
93
- cols.each_with_index do |c,i|
94
- reflection = model.reflections.detect {|k,v| v.foreign_key == c }
95
- if reflection
96
- column c do |o|
97
- klass.link_record(self,o.send(reflection.first))
98
- end
99
- else
100
- column c
101
- end
102
- end
103
- actions
104
- end
105
-
106
- show do
107
- instance = self.send(model_name)
108
-
109
- attributes_table do
110
- model.columns.each do |c|
111
- next if (c.name =~ /password/)
112
- reflection = model.reflections.detect {|k,v| v.foreign_key == c.name }
113
- if reflection
114
- row c.name do |o|
115
- klass.link_record(self,instance.send(reflection.first))
116
- end
117
- else
118
- row c.name
119
- end
120
-
121
- end
122
-
123
- nested_config.each do |assoc,options|
124
- panel assoc.capitalize do
125
- table_for instance.send(assoc) do
126
- options[:columns].each do |c|
127
- if options[:class].reflections[c]
128
- column( c ) do |r|
129
- klass.link_record(self,r.send(c)) if r
130
- end
131
- else
132
- column c
133
- end
134
- end
135
-
136
- admin_route = begin url_for(['admin', options[:class].name.underscore]) rescue false end
137
- if admin_route
138
- column 'actions' do |child|
139
- span link_to "View", url_for(['admin', child])
140
- span link_to "Edit", url_for(['edit','admin',child])
141
- span link_to "Delete", url_for(['admin',child]), method: :delete, confirm: "Are you sure you want to delete this?"
142
- end
143
- end
144
- end
145
- end
146
- end
147
- end
148
- end
149
-
150
- permit_params klass.params_list(model, klass.include_virtual_attributes) + [Hash[nested_config.map{|assoc,o|
151
- ["#{assoc}_attributes", o[:params]+[(o[:allow_destroy] ? :_destroy : '')] ]
152
- }]]
153
-
154
- form do |f|
155
- f.semantic_errors *f.object.errors.messages.keys
156
- f.actions
157
-
158
- klass.column_list(model, klass.include_virtual_attributes).each do |column|
159
- if column == model.primary_key
160
- elsif klass.polymorphic?(model,column)
161
- f.input column+"_assign", collection: model.send("#{column}_assign_options")
162
- elsif model.respond_to?("options_for_#{column}")
163
- f.input column, collection: model.send("options_for_#{column}", f.object)
164
- else
165
- f.input column
166
- end
167
- end
168
-
169
- div { '&nbsp'.html_safe }
170
-
171
- nested_config.each do |assoc,options|
172
- aclass = options[:class]
173
- columns = options[:columns]-[aclass.primary_key]
174
- f.inputs do
175
- f.has_many assoc, allow_destroy: options[:allow_destroy] do |r|
176
- columns.each do |c|
177
- if c == model_name || c == options[:polymorphic_reference]
178
- # the join to the parent is implicit
179
- elsif klass.polymorphic?(aclass,c)
180
- r.input "#{c}_assign", collection: aclass.send("#{c}_assign_options")
181
- elsif aclass.reflections[c] && aclass.respond_to?("options_for_#{c}")
182
- # If the class has an options_for_<column> method defined use that
183
- # rather than the default behavior, pass the instance for scoping,
184
- # e.g. UserProjectJob.options_for_job is scoped by the Project's
185
- # jobs:
186
- r.input c, collection: aclass.send("options_for_#{c}",f.object)
187
- else
188
- r.input c
189
- end
190
- end
191
- end
192
- end
193
- end
194
- end
195
-
196
- end
197
- end
198
- end
199
- end
200
- end
1
+ module IntrospectiveAdmin
2
+ class Base
3
+ # Generate an active admin interface by introspecting on the models.
4
+
5
+ # For polymorphic associations set up virtual 'assign' attributes on the model like so:
6
+ #
7
+ # def <polymorphism>_assign
8
+ # "#{<polymorphism>_type}-#{<polymorphism>_id}"
9
+ # end
10
+ # def <polymorphism>_assign=(value)
11
+ # self.<polymorphism>_type,self.<polymorphism>_id = value.split('-')
12
+ # end
13
+ #
14
+ # And designate the selection options in a class method, you can pass the
15
+ # target model to modify the options list accordingly
16
+ #
17
+ # def self.<polymorphism>_options(model=nil)
18
+ # (Model.all + SecondModel.all).map { |i| [ i.name, "#{i.class}-#{i.id}"] }
19
+ # end
20
+
21
+ class << self
22
+
23
+ def exclude_params
24
+ [] # do not display the field in the index page and forms.
25
+ end
26
+
27
+ def include_virtual_attributes
28
+ [] #
29
+ end
30
+
31
+ def polymorphic?(model,column)
32
+ (model.reflections[column.sub(/_id$/,'')].try(:options)||{})[:polymorphic]
33
+ end
34
+
35
+ def column_list(model, extras=[])
36
+ model.columns.map {|c|
37
+ ref_name = c.name.sub(/(_type|_id)$/,'')
38
+ model.reflections[ref_name] ? ref_name : c.name
39
+ }.uniq-['created_at','updated_at']-exclude_params+extras
40
+ end
41
+
42
+ def params_list(model, extras=[])
43
+ model.columns.map {|c|
44
+ polymorphic?(model,c.name) ? c.name.sub(/_id$/,'')+"_assign" : c.name
45
+ }+extras
46
+ end
47
+
48
+ def link_record(dsl, record)
49
+ link_text = record.try(:name) || record.try(:title) || record.class.to_s
50
+ link_href = begin dsl.send("admin_#{record.class.name.underscore}_path", record.id) rescue false end
51
+ if link_href
52
+ dsl.link_to link_text, link_href
53
+ elsif link_text
54
+ link_text
55
+ else
56
+ record
57
+ end
58
+ end
59
+
60
+ def register(model, &block)
61
+ # Defining activeadmin pages will break pending migrations:
62
+ begin ActiveRecord::Migration.check_all_pending! rescue return end
63
+
64
+ klass = self
65
+ model_name = model.to_s.underscore
66
+ nested_config = Hash[model.nested_attributes_options.reject {|name,o|
67
+ klass.exclude_params.include?("#{name}_attributes")
68
+ }.map {|assoc,options|
69
+ reflection = model.reflections[assoc.to_s]
70
+ reflection_class = reflection.class_name.constantize
71
+ # merge the options of the nested attribute and relationship declarations
72
+ options = options.merge(reflection_class.reflections[assoc.to_s].try(:options) || {})
73
+ options[:class] = reflection_class
74
+ options[:columns] = klass.column_list(reflection_class)
75
+ options[:params] = klass.params_list(reflection_class)
76
+ options[:reflection] = reflection
77
+ options[:polymorphic_reference] = reflection.options[:as].to_s
78
+ [assoc, options]
79
+ }]
80
+
81
+ ActiveAdmin.register model do
82
+ instance_eval &block if block_given? # Evalutate the passed black for overrides to the defaults
83
+
84
+ controller do
85
+ def scoped_collection
86
+ super.includes super.nested_attributes_options.keys
87
+ end
88
+ end
89
+
90
+ index do
91
+ selectable_column
92
+ cols = model.columns.map(&:name)-klass.exclude_params
93
+ cols.each_with_index do |c,i|
94
+ reflection = model.reflections.detect {|k,v| v.foreign_key == c }
95
+ if reflection
96
+ column c do |o|
97
+ klass.link_record(self,o.send(reflection.first))
98
+ end
99
+ else
100
+ column c
101
+ end
102
+ end
103
+ actions
104
+ end
105
+
106
+ show do
107
+ instance = self.send(model_name)
108
+
109
+ attributes_table do
110
+ model.columns.each do |c|
111
+ next if (c.name =~ /password/)
112
+ reflection = model.reflections.detect {|k,v| v.foreign_key == c.name }
113
+ if reflection
114
+ row c.name do |o|
115
+ klass.link_record(self,instance.send(reflection.first))
116
+ end
117
+ else
118
+ row c.name
119
+ end
120
+
121
+ end
122
+
123
+ nested_config.each do |assoc,options|
124
+ panel assoc.capitalize do
125
+ table_for instance.send(assoc) do
126
+ options[:columns].each do |c|
127
+ if options[:class].reflections[c]
128
+ column( c ) do |r|
129
+ klass.link_record(self,r.send(c)) if r
130
+ end
131
+ else
132
+ column c
133
+ end
134
+ end
135
+
136
+ admin_route = begin url_for(['admin', options[:class].name.underscore]) rescue false end
137
+ if admin_route
138
+ column 'actions' do |child|
139
+ span link_to "View", url_for(['admin', child])
140
+ span link_to "Edit", url_for(['edit','admin',child])
141
+ span link_to "Delete", url_for(['admin',child]), method: :delete, confirm: "Are you sure you want to delete this?"
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ permit_params klass.params_list(model, klass.include_virtual_attributes) + [Hash[nested_config.map{|assoc,o|
151
+ ["#{assoc}_attributes", o[:params]+[(o[:allow_destroy] ? :_destroy : '')] ]
152
+ }]]
153
+
154
+ form do |f|
155
+ f.semantic_errors *f.object.errors.messages.keys
156
+ f.actions
157
+
158
+ klass.column_list(model, klass.include_virtual_attributes).each do |column|
159
+ if column == model.primary_key
160
+ elsif klass.polymorphic?(model,column)
161
+ f.input column+"_assign", collection: model.send("#{column}_assign_options")
162
+ elsif model.respond_to?("options_for_#{column}")
163
+ f.input column, collection: model.send("options_for_#{column}", f.object)
164
+ else
165
+ f.input column
166
+ end
167
+ end
168
+
169
+ div { '&nbsp'.html_safe }
170
+
171
+ nested_config.each do |assoc,options|
172
+ aclass = options[:class]
173
+ columns = options[:columns]-[aclass.primary_key]
174
+ f.inputs do
175
+ f.has_many assoc, allow_destroy: options[:allow_destroy] do |r|
176
+ columns.each do |c|
177
+ if c == model_name || c == options[:polymorphic_reference]
178
+ # the join to the parent is implicit
179
+ elsif klass.polymorphic?(aclass,c)
180
+ r.input "#{c}_assign", collection: aclass.send("#{c}_assign_options")
181
+ elsif aclass.reflections[c] && aclass.respond_to?("options_for_#{c}")
182
+ # If the class has an options_for_<column> method defined use that
183
+ # rather than the default behavior, pass the instance for scoping,
184
+ # e.g. UserProjectJob.options_for_job is scoped by the Project's
185
+ # jobs:
186
+ r.input c, collection: aclass.send("options_for_#{c}",f.object)
187
+ else
188
+ r.input c
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
@@ -1,3 +1,3 @@
1
- module IntrospectiveAdmin
2
- VERSION = "0.1.0"
3
- end
1
+ module IntrospectiveAdmin
2
+ VERSION = "0.9.0"
3
+ end