admin_assistant 0.0.1
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/MIT-LICENSE +20 -0
- data/README +43 -0
- data/Rakefile +28 -0
- data/install.rb +1 -0
- data/lib/admin_assistant/builder.rb +104 -0
- data/lib/admin_assistant/column.rb +383 -0
- data/lib/admin_assistant/form_view.rb +124 -0
- data/lib/admin_assistant/helper.rb +7 -0
- data/lib/admin_assistant/index.rb +181 -0
- data/lib/admin_assistant/request.rb +183 -0
- data/lib/admin_assistant.rb +172 -0
- data/lib/images/sort-asc.png +0 -0
- data/lib/images/sort-desc.png +0 -0
- data/lib/stylesheets/admin_assistant.css +75 -0
- data/lib/views/form.html.erb +31 -0
- data/lib/views/index.html.erb +92 -0
- data/tasks/admin_assistant_tasks.rake +4 -0
- data/uninstall.rb +1 -0
- metadata +89 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 [name of plugin creator]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
admin_assistant
|
2
|
+
===============
|
3
|
+
|
4
|
+
admin_assistant is a Rails plugin that automates a lot of features typically
|
5
|
+
needed in admin interfaces. Current features include:
|
6
|
+
|
7
|
+
* Your basic CReate / Update / Delete
|
8
|
+
* Index with pagination and field ordering
|
9
|
+
* Search, either by all text fields or by specific fields
|
10
|
+
* Live querying of models to generate forms and indexes, meaning that adding
|
11
|
+
new columns to your admin controllers is easy
|
12
|
+
* Simple handling of belongs_to association via drop-down selects
|
13
|
+
* Built-in support for Paperclip and FileColumn
|
14
|
+
|
15
|
+
I'm following a few design principles in building this:
|
16
|
+
|
17
|
+
* admin_assistant's specs are written through an actual Rails app: I believe
|
18
|
+
this is the only sensible way to test a Rails plugin that deals with lots of
|
19
|
+
controller actions and views.
|
20
|
+
* admin_assistant will support multiple versions of Rails, so I'm experimenting
|
21
|
+
with a spec suite that can be run against all versions with one Rake task.
|
22
|
+
* admin_assistant will be severely hookable. If you're copying and pasting
|
23
|
+
something out of vendor/plugins/admin_assistant, that's a design flaw.
|
24
|
+
* admin_assistant will be minimally invasive to the rest of the Rails app. It
|
25
|
+
does not require that you add strange one-off methods to an important model
|
26
|
+
just to do something in an admin controller. And I'll try to avoid doing
|
27
|
+
anything silly like alias_method_chaining anything on ActionController::Base.
|
28
|
+
* admin_assistant will have some safe defaults, including turning off the
|
29
|
+
destroy action by default, and not filling in dates and times with the
|
30
|
+
current date or time (which is almost always useless).
|
31
|
+
|
32
|
+
There are also some features I'm skimping on right now:
|
33
|
+
|
34
|
+
* Super-pretty CSS: Because I suck at CSS. Submissions of themes are welcome
|
35
|
+
though.
|
36
|
+
* Super-fancy Ajax: Because I think it's easy to do this wrong. But there will
|
37
|
+
be some Ajax at some point I spose.
|
38
|
+
|
39
|
+
Basically, this plugin should act like a really great administrative assistant
|
40
|
+
in your office. It tries to be extremely helpful, but it won't get underfoot or
|
41
|
+
tell you how to do your job.
|
42
|
+
|
43
|
+
Copyright (c) 2009 Francis Hwang, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'spec/rake/spectask'
|
5
|
+
|
6
|
+
desc 'Default: run all specs across all supported Rails gem versions.'
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
desc 'Run all specs across all supported Rails gem versions.'
|
10
|
+
task :spec do
|
11
|
+
%w(2.1.2 2.2.2 2.3.2).each do |rails_gem_version|
|
12
|
+
puts "*** RAILS #{rails_gem_version} ***"
|
13
|
+
cmd = "cd test_rails_app && RAILS_GEM_VERSION=#{rails_gem_version} rake"
|
14
|
+
puts cmd
|
15
|
+
puts `#{cmd}`
|
16
|
+
puts
|
17
|
+
puts
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Generate documentation for the admin_assistant plugin.'
|
22
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
23
|
+
rdoc.rdoc_dir = 'rdoc'
|
24
|
+
rdoc.title = 'AdminAssistant'
|
25
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
26
|
+
rdoc.rdoc_files.include('README')
|
27
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
28
|
+
end
|
data/install.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Install hook code here
|
@@ -0,0 +1,104 @@
|
|
1
|
+
class AdminAssistant
|
2
|
+
class Builder
|
3
|
+
attr_reader :admin_assistant
|
4
|
+
|
5
|
+
def initialize(admin_assistant)
|
6
|
+
@admin_assistant = admin_assistant
|
7
|
+
end
|
8
|
+
|
9
|
+
def actions(*a)
|
10
|
+
if a.empty?
|
11
|
+
@admin_assistant.actions
|
12
|
+
else
|
13
|
+
@admin_assistant.actions = a
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def inputs
|
18
|
+
@admin_assistant.form_settings.inputs
|
19
|
+
end
|
20
|
+
|
21
|
+
def label(column, label)
|
22
|
+
@admin_assistant.custom_column_labels[column.to_s] = label
|
23
|
+
end
|
24
|
+
|
25
|
+
def form
|
26
|
+
yield @admin_assistant.form_settings
|
27
|
+
end
|
28
|
+
|
29
|
+
def index
|
30
|
+
yield @admin_assistant.index_settings
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Settings
|
35
|
+
attr_reader :column_names
|
36
|
+
|
37
|
+
def initialize(admin_assistant)
|
38
|
+
@admin_assistant = admin_assistant
|
39
|
+
end
|
40
|
+
|
41
|
+
def columns(*args)
|
42
|
+
@column_names = args
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class FormSettings < Settings
|
47
|
+
attr_reader :inputs, :submit_buttons
|
48
|
+
|
49
|
+
def initialize(admin_assistant)
|
50
|
+
super
|
51
|
+
@inputs = {}
|
52
|
+
@submit_buttons = []
|
53
|
+
@read_only = []
|
54
|
+
end
|
55
|
+
|
56
|
+
def read_only(*args)
|
57
|
+
if args.empty?
|
58
|
+
@read_only
|
59
|
+
else
|
60
|
+
args.each do |arg| @read_only << arg.to_s; end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class IndexSettings < Settings
|
66
|
+
attr_reader :actions, :link_to_args, :search_fields, :sort_by
|
67
|
+
attr_accessor :total_entries
|
68
|
+
|
69
|
+
def initialize(admin_assistant)
|
70
|
+
super
|
71
|
+
@actions = {}
|
72
|
+
@sort_by = 'id desc'
|
73
|
+
@boolean_labels = {}
|
74
|
+
@link_to_args = {}
|
75
|
+
@search_fields = []
|
76
|
+
end
|
77
|
+
|
78
|
+
def boolean_labels(*args)
|
79
|
+
if args.size == 1
|
80
|
+
args.first.each do |column_name, pairs|
|
81
|
+
@boolean_labels[column_name.to_s] = pairs
|
82
|
+
end
|
83
|
+
else
|
84
|
+
@boolean_labels
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def conditions(&block)
|
89
|
+
block ? (@conditions = block) : @conditions
|
90
|
+
end
|
91
|
+
|
92
|
+
def search(*fields)
|
93
|
+
@search_fields = fields
|
94
|
+
end
|
95
|
+
|
96
|
+
def sort_by(*sb)
|
97
|
+
if sb.empty?
|
98
|
+
@sort_by
|
99
|
+
else
|
100
|
+
@sort_by = sb
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,383 @@
|
|
1
|
+
class AdminAssistant
|
2
|
+
class Column
|
3
|
+
attr_accessor :custom_label
|
4
|
+
|
5
|
+
def view(action_view, opts = {})
|
6
|
+
klass = self.class.const_get 'View'
|
7
|
+
klass.new self, action_view, opts
|
8
|
+
end
|
9
|
+
|
10
|
+
class View < Delegator
|
11
|
+
attr_reader :sort_order
|
12
|
+
|
13
|
+
def initialize(column, action_view, opts)
|
14
|
+
super(column)
|
15
|
+
@column, @action_view, @opts = column, action_view, opts
|
16
|
+
@input = opts[:input]
|
17
|
+
@link_to_args = opts[:link_to_args]
|
18
|
+
@search = opts[:search]
|
19
|
+
@sort_order = opts[:sort_order]
|
20
|
+
end
|
21
|
+
|
22
|
+
def __getobj__
|
23
|
+
@column
|
24
|
+
end
|
25
|
+
|
26
|
+
def __setobj__(column)
|
27
|
+
@column = column
|
28
|
+
end
|
29
|
+
|
30
|
+
def form_value(record)
|
31
|
+
value_method = "#{@column.name}_value"
|
32
|
+
if @action_view.respond_to?(value_method)
|
33
|
+
@action_view.send value_method, record
|
34
|
+
else
|
35
|
+
field_value record
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def index_header_css_class
|
40
|
+
"sort #{sort_order}" if sort_order
|
41
|
+
end
|
42
|
+
|
43
|
+
def index_td_css_class
|
44
|
+
'sort' if sort_order
|
45
|
+
end
|
46
|
+
|
47
|
+
def index_html(record)
|
48
|
+
html_for_index_method = "#{name}_html_for_index"
|
49
|
+
html = if @action_view.respond_to?(html_for_index_method)
|
50
|
+
@action_view.send html_for_index_method, record
|
51
|
+
elsif @link_to_args
|
52
|
+
@action_view.link_to(
|
53
|
+
@action_view.send(:h, index_value(record)),
|
54
|
+
@link_to_args.call(record)
|
55
|
+
)
|
56
|
+
else
|
57
|
+
@action_view.send(:h, index_value(record))
|
58
|
+
end
|
59
|
+
html = ' ' if html.blank?
|
60
|
+
html
|
61
|
+
end
|
62
|
+
|
63
|
+
def index_value(record)
|
64
|
+
value_method = "#{@column.name}_value"
|
65
|
+
if @action_view.respond_to?(value_method)
|
66
|
+
@action_view.send value_method, record
|
67
|
+
else
|
68
|
+
field_value record
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def label
|
73
|
+
if @column.custom_label
|
74
|
+
@column.custom_label
|
75
|
+
elsif @column.name.to_s == 'id'
|
76
|
+
'ID'
|
77
|
+
else
|
78
|
+
@column.name.to_s.capitalize.gsub(/_/, ' ')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def next_sort_params
|
83
|
+
name_for_sort = name
|
84
|
+
next_sort_order = 'asc'
|
85
|
+
if sort_order
|
86
|
+
if sort_order == 'asc'
|
87
|
+
next_sort_order = 'desc'
|
88
|
+
else
|
89
|
+
name_for_sort = nil
|
90
|
+
next_sort_order = nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
{:sort => name_for_sort, :sort_order => next_sort_order}
|
94
|
+
end
|
95
|
+
|
96
|
+
def paperclip?
|
97
|
+
@column.is_a?(PaperclipColumn)
|
98
|
+
end
|
99
|
+
|
100
|
+
def sort_possible?
|
101
|
+
@column.is_a?(ActiveRecordColumn) || @column.is_a?(BelongsToColumn)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class ActiveRecordColumn < Column
|
107
|
+
attr_accessor :search_terms
|
108
|
+
|
109
|
+
def initialize(ar_column)
|
110
|
+
@ar_column = ar_column
|
111
|
+
end
|
112
|
+
|
113
|
+
def add_to_query(ar_query)
|
114
|
+
unless @search_terms.blank?
|
115
|
+
ar_query.boolean_join = :and
|
116
|
+
case sql_type
|
117
|
+
when :boolean
|
118
|
+
ar_query.condition_sqls << "#{name} = ?"
|
119
|
+
ar_query.bind_vars << search_value
|
120
|
+
else
|
121
|
+
ar_query.condition_sqls << "#{name} like ?"
|
122
|
+
ar_query.bind_vars << "%#{@search_terms}%"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def contains?(column_name)
|
128
|
+
column_name.to_s == @ar_column.name
|
129
|
+
end
|
130
|
+
|
131
|
+
def name
|
132
|
+
@ar_column.name
|
133
|
+
end
|
134
|
+
|
135
|
+
def search_value
|
136
|
+
case sql_type
|
137
|
+
when :boolean
|
138
|
+
@search_terms.blank? ? nil : (@search_terms == 'true')
|
139
|
+
else
|
140
|
+
@search_terms
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def sql_type
|
145
|
+
@ar_column.type
|
146
|
+
end
|
147
|
+
|
148
|
+
class View < AdminAssistant::Column::View
|
149
|
+
def initialize(column, action_view, opts)
|
150
|
+
super
|
151
|
+
@boolean_labels = opts[:boolean_labels]
|
152
|
+
end
|
153
|
+
|
154
|
+
def add_to_form(form)
|
155
|
+
case @input || @column.sql_type
|
156
|
+
when :text
|
157
|
+
form.text_area name
|
158
|
+
when :boolean
|
159
|
+
form.check_box name
|
160
|
+
when :datetime
|
161
|
+
form.datetime_select name, :include_blank => true
|
162
|
+
when :date
|
163
|
+
form.date_select name, :include_blank => true
|
164
|
+
when :us_state
|
165
|
+
form.select(
|
166
|
+
name, ordered_us_state_names_and_codes, :include_blank => true
|
167
|
+
)
|
168
|
+
else
|
169
|
+
form.text_field name
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def field_value(record)
|
174
|
+
record.send(name) if record.respond_to?(name)
|
175
|
+
end
|
176
|
+
|
177
|
+
def index_value(record)
|
178
|
+
value = super
|
179
|
+
if @boolean_labels
|
180
|
+
value = value ? @boolean_labels.first : @boolean_labels.last
|
181
|
+
end
|
182
|
+
value
|
183
|
+
end
|
184
|
+
|
185
|
+
def ordered_us_state_names_and_codes
|
186
|
+
{
|
187
|
+
'Alabama' => 'AL', 'Alaska' => 'AK', 'Arizona' => 'AZ',
|
188
|
+
'Arkansas' => 'AR', 'California' => 'CA', 'Colorado' => 'CO',
|
189
|
+
'Connecticut' => 'CT', 'Delaware' => 'DE',
|
190
|
+
'District of Columbia' => 'DC', 'Florida' => 'FL', 'Georgia' => 'GA',
|
191
|
+
'Hawaii' => 'HI', 'Idaho' => 'ID', 'Illinois' => 'IL',
|
192
|
+
'Indiana' => 'IN', 'Iowa' => 'IA', 'Kansas' => 'KS',
|
193
|
+
'Kentucky' => 'KY', 'Louisiana' => 'LA', 'Maine' => 'ME',
|
194
|
+
'Maryland' => 'MD', 'Massachusetts' => 'MA', 'Michigan' => 'MI',
|
195
|
+
'Minnesota' => 'MN', 'Mississippi' => 'MS', 'Missouri' => 'MO',
|
196
|
+
'Montana' => 'MT', 'Nebraska' => 'NE', 'Nevada' => 'NV',
|
197
|
+
'New Hampshire' => 'NH', 'New Jersey' => 'NJ', 'New Mexico' => 'NM',
|
198
|
+
'New York' => 'NY', 'North Carolina' => 'NC', 'North Dakota' => 'ND',
|
199
|
+
'Ohio' => 'OH', 'Oklahoma' => 'OK', 'Oregon' => 'OR',
|
200
|
+
'Pennsylvania' => 'PA', 'Puerto Rico' => 'PR',
|
201
|
+
'Rhode Island' => 'RI', 'South Carolina' => 'SC',
|
202
|
+
'South Dakota' => 'SD', 'Tennessee' => 'TN', 'Texas' => 'TX',
|
203
|
+
'Utah' => 'UT', 'Vermont' => 'VT', 'Virginia' => 'VA',
|
204
|
+
'Washington' => 'WA', 'West Virginia' => 'WV', 'Wisconsin' => 'WI',
|
205
|
+
'Wyoming' => 'WY'
|
206
|
+
}.sort_by { |name, code| name }
|
207
|
+
end
|
208
|
+
|
209
|
+
def search_html
|
210
|
+
input = case @column.sql_type
|
211
|
+
when :boolean
|
212
|
+
opts = [['', nil]]
|
213
|
+
if @boolean_labels
|
214
|
+
opts << [@boolean_labels.first, true]
|
215
|
+
opts << [@boolean_labels.last, false]
|
216
|
+
else
|
217
|
+
opts << ['true', true]
|
218
|
+
opts << ['false', false]
|
219
|
+
end
|
220
|
+
@action_view.select("search", name, opts)
|
221
|
+
else
|
222
|
+
@action_view.text_field_tag("search[#{name}]", @search[name])
|
223
|
+
end
|
224
|
+
"<p><label>#{label}</label> <br/>#{input}</p>"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
class AdminAssistantColumn < Column
|
230
|
+
attr_reader :name
|
231
|
+
|
232
|
+
def initialize(name)
|
233
|
+
@name = name.to_s
|
234
|
+
end
|
235
|
+
|
236
|
+
def contains?(column_name)
|
237
|
+
column_name.to_s == @name
|
238
|
+
end
|
239
|
+
|
240
|
+
class View < AdminAssistant::Column::View
|
241
|
+
def field_value(record)
|
242
|
+
nil
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
class BelongsToColumn < Column
|
248
|
+
def initialize(belongs_to_assoc)
|
249
|
+
@belongs_to_assoc = belongs_to_assoc
|
250
|
+
end
|
251
|
+
|
252
|
+
def associated_class
|
253
|
+
@belongs_to_assoc.klass
|
254
|
+
end
|
255
|
+
|
256
|
+
def association_foreign_key
|
257
|
+
@belongs_to_assoc.association_foreign_key
|
258
|
+
end
|
259
|
+
|
260
|
+
def contains?(column_name)
|
261
|
+
column_name.to_s == name
|
262
|
+
end
|
263
|
+
|
264
|
+
def default_name_method
|
265
|
+
[:name, :title, :login, :username].detect { |m|
|
266
|
+
associated_class.columns.any? { |column| column.name.to_s == m.to_s }
|
267
|
+
}
|
268
|
+
end
|
269
|
+
|
270
|
+
def name
|
271
|
+
@belongs_to_assoc.name.to_s
|
272
|
+
end
|
273
|
+
|
274
|
+
def order_sql_field
|
275
|
+
sql = "#{@belongs_to_assoc.table_name}. "
|
276
|
+
sql << if default_name_method
|
277
|
+
default_name_method.to_s
|
278
|
+
else
|
279
|
+
@belongs_to_assoc.association_foreign_key
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
class View < AdminAssistant::Column::View
|
284
|
+
def add_to_form(form)
|
285
|
+
form.select(
|
286
|
+
association_foreign_key,
|
287
|
+
associated_class.
|
288
|
+
find(:all).
|
289
|
+
sort_by { |model| model.send(default_name_method) }.
|
290
|
+
map { |model| [model.send(default_name_method), model.id] }
|
291
|
+
)
|
292
|
+
end
|
293
|
+
|
294
|
+
def field_value(record)
|
295
|
+
assoc_value = record.send name
|
296
|
+
if assoc_value.respond_to?(:name_for_admin_assistant)
|
297
|
+
assoc_value.name_for_admin_assistant
|
298
|
+
elsif assoc_value && default_name_method
|
299
|
+
assoc_value.send default_name_method
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
class DefaultSearchColumn < Column
|
306
|
+
attr_reader :terms
|
307
|
+
|
308
|
+
def initialize(terms, model_class)
|
309
|
+
@terms, @model_class = terms, model_class
|
310
|
+
end
|
311
|
+
|
312
|
+
def add_to_query(ar_query)
|
313
|
+
unless @terms.blank?
|
314
|
+
ar_query.boolean_join = :or
|
315
|
+
searchable_columns.each do |column|
|
316
|
+
ar_query.condition_sqls << "#{column.name} like ?"
|
317
|
+
ar_query.bind_vars << "%#{@terms}%"
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def searchable_columns
|
323
|
+
@model_class.columns.select { |column|
|
324
|
+
[:string, :text].include?(column.type)
|
325
|
+
}
|
326
|
+
end
|
327
|
+
|
328
|
+
class View < AdminAssistant::Column::View
|
329
|
+
def search_html
|
330
|
+
@action_view.text_field_tag("search", @column.terms)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
class FileColumnColumn < Column
|
336
|
+
attr_reader :name
|
337
|
+
|
338
|
+
def initialize(name)
|
339
|
+
@name = name.to_s
|
340
|
+
end
|
341
|
+
|
342
|
+
def contains?(column_name)
|
343
|
+
column_name.to_s == @name
|
344
|
+
end
|
345
|
+
|
346
|
+
class View < AdminAssistant::Column::View
|
347
|
+
def add_to_form(form)
|
348
|
+
form.file_field name
|
349
|
+
end
|
350
|
+
|
351
|
+
def index_html(record)
|
352
|
+
@action_view.instance_variable_set :@record, record
|
353
|
+
@action_view.image_tag(
|
354
|
+
@action_view.url_for_file_column('record', @column.name)
|
355
|
+
)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
class PaperclipColumn < Column
|
361
|
+
attr_reader :name
|
362
|
+
|
363
|
+
def initialize(name)
|
364
|
+
@name = name.to_s
|
365
|
+
end
|
366
|
+
|
367
|
+
def contains?(column_name)
|
368
|
+
column_name.to_s == @name ||
|
369
|
+
column_name.to_s =~
|
370
|
+
/^#{@name}_(file_name|content_type|file_size|updated_at)$/
|
371
|
+
end
|
372
|
+
|
373
|
+
class View < AdminAssistant::Column::View
|
374
|
+
def add_to_form(form)
|
375
|
+
form.file_field name
|
376
|
+
end
|
377
|
+
|
378
|
+
def index_html(record)
|
379
|
+
@action_view.image_tag record.send(@column.name).url
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
class AdminAssistant
|
2
|
+
class FormView
|
3
|
+
def initialize(record, admin_assistant, action_view)
|
4
|
+
@record, @admin_assistant, @action_view =
|
5
|
+
record, admin_assistant, action_view
|
6
|
+
end
|
7
|
+
|
8
|
+
def action
|
9
|
+
if %w(new create).include?(controller.action_name)
|
10
|
+
'create'
|
11
|
+
else
|
12
|
+
'update'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def after_column_html(column)
|
17
|
+
if after = render_from_custom_template("_after_#{column.name}_input")
|
18
|
+
after
|
19
|
+
else
|
20
|
+
helper_method = "after_#{column.name}_input"
|
21
|
+
if @action_view.respond_to?(helper_method)
|
22
|
+
@action_view.send(helper_method, @record)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def column_html(column, rails_form)
|
28
|
+
hff = render_from_custom_template "_#{column.name}_input"
|
29
|
+
hff ||= column_html_from_helper_method(column)
|
30
|
+
hff ||= if settings.read_only.include?(column.name)
|
31
|
+
column.form_value(@record)
|
32
|
+
elsif column.respond_to?(:add_to_form)
|
33
|
+
column.add_to_form(rails_form)
|
34
|
+
else
|
35
|
+
virtual_column_html column
|
36
|
+
end
|
37
|
+
if ah = after_column_html(column)
|
38
|
+
hff << ah
|
39
|
+
end
|
40
|
+
hff
|
41
|
+
end
|
42
|
+
|
43
|
+
def column_html_from_helper_method(column)
|
44
|
+
html_method = "#{column.name}_html_for_form"
|
45
|
+
if @action_view.respond_to?(html_method)
|
46
|
+
@action_view.send(html_method, @record)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def column_names
|
51
|
+
settings.column_names ||
|
52
|
+
model_class.columns.reject { |ar_column|
|
53
|
+
%w(id created_at updated_at).include?(ar_column.name)
|
54
|
+
}.map { |ar_column|
|
55
|
+
@admin_assistant.column_name_or_assoc_name(ar_column.name)
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def columns
|
60
|
+
@admin_assistant.columns(column_names).map { |c|
|
61
|
+
c.view(@action_view, :input => settings.inputs[c.name.to_sym])
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def controller
|
66
|
+
@action_view.controller
|
67
|
+
end
|
68
|
+
|
69
|
+
def extra_submit_buttons
|
70
|
+
settings.submit_buttons
|
71
|
+
end
|
72
|
+
|
73
|
+
def form_for_args
|
74
|
+
args = {:url => {:action => action, :id => @record.id}}
|
75
|
+
unless @admin_assistant.paperclip_attachments.empty? &&
|
76
|
+
@admin_assistant.file_columns.empty?
|
77
|
+
args[:html] = {:multipart => true}
|
78
|
+
end
|
79
|
+
args
|
80
|
+
end
|
81
|
+
|
82
|
+
def model_class
|
83
|
+
@admin_assistant.model_class
|
84
|
+
end
|
85
|
+
|
86
|
+
def render_from_custom_template(slug)
|
87
|
+
template = File.join(
|
88
|
+
RAILS_ROOT, 'app/views', controller.controller_path, "#{slug}.html.erb"
|
89
|
+
)
|
90
|
+
if File.exist?(template)
|
91
|
+
@action_view.render(
|
92
|
+
:file => template,
|
93
|
+
:locals => {model_class.name.underscore.to_sym => @record}
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def settings
|
99
|
+
@admin_assistant.form_settings
|
100
|
+
end
|
101
|
+
|
102
|
+
def submit_value
|
103
|
+
action.capitalize
|
104
|
+
end
|
105
|
+
|
106
|
+
def title
|
107
|
+
(@record.id ? "Edit" : "New") + " #{@admin_assistant.model_class_name}"
|
108
|
+
end
|
109
|
+
|
110
|
+
def virtual_column_html(column)
|
111
|
+
input_name = "#{model_class.name.underscore}[#{column.name}]"
|
112
|
+
input_type = settings.inputs[column.name.to_sym]
|
113
|
+
fv = column.form_value @record
|
114
|
+
if input_type
|
115
|
+
if input_type == :check_box
|
116
|
+
@action_view.send(:check_box_tag, input_name, '1', fv) +
|
117
|
+
@action_view.send(:hidden_field_tag, input_name, '0')
|
118
|
+
end
|
119
|
+
else
|
120
|
+
@action_view.send(:text_field_tag, input_name, fv)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|