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