hobo 0.6.2 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/hobo +21 -22
- data/hobo_files/plugin/CHANGES.txt +429 -4
- data/hobo_files/plugin/Rakefile +2 -2
- data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +6 -5
- data/hobo_files/plugin/generators/hobo_front_controller/templates/search.dryml +2 -2
- data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +20 -15
- data/hobo_files/plugin/generators/hobo_model/templates/model.rb +1 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/controller.rb +2 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_base.css +1 -2
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.css +4 -3
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.js +94 -12
- data/hobo_files/plugin/generators/hobo_rapid/templates/lowpro.js +5 -183
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/stylesheets/application.css +1 -1
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +23 -1
- data/hobo_files/plugin/generators/hobo_user_controller/templates/controller.rb +2 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +3 -1
- data/hobo_files/plugin/init.rb +18 -7
- data/hobo_files/plugin/lib/active_record/has_many_association.rb +2 -2
- data/hobo_files/plugin/lib/extensions.rb +56 -12
- data/hobo_files/plugin/lib/hobo.rb +25 -88
- data/hobo_files/plugin/lib/hobo/composite_model.rb +2 -0
- data/hobo_files/plugin/lib/hobo/controller.rb +40 -20
- data/hobo_files/plugin/lib/hobo/dryml.rb +122 -106
- data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +2 -1
- data/hobo_files/plugin/lib/hobo/dryml/part_context.rb +3 -2
- data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +19 -3
- data/hobo_files/plugin/lib/hobo/dryml/template.rb +40 -25
- data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +41 -20
- data/hobo_files/plugin/lib/hobo/email_address.rb +4 -1
- data/hobo_files/plugin/lib/hobo/enum_string.rb +50 -0
- data/hobo_files/plugin/lib/hobo/field_declaration_dsl.rb +36 -0
- data/hobo_files/plugin/lib/hobo/field_spec.rb +4 -7
- data/hobo_files/plugin/lib/hobo/hobo_helper.rb +47 -44
- data/hobo_files/plugin/lib/hobo/html_string.rb +2 -0
- data/hobo_files/plugin/lib/hobo/markdown_string.rb +2 -0
- data/hobo_files/plugin/lib/hobo/model.rb +158 -89
- data/hobo_files/plugin/lib/hobo/model_controller.rb +422 -376
- data/hobo_files/plugin/lib/hobo/model_queries.rb +1 -1
- data/hobo_files/plugin/lib/hobo/model_router.rb +174 -0
- data/hobo_files/plugin/lib/hobo/password_string.rb +2 -0
- data/hobo_files/plugin/lib/hobo/percentage.rb +14 -0
- data/hobo_files/plugin/lib/hobo/plugins.rb +4 -4
- data/hobo_files/plugin/lib/hobo/rapid_helper.rb +10 -2
- data/hobo_files/plugin/lib/hobo/text.rb +3 -3
- data/hobo_files/plugin/lib/hobo/textile_string.rb +2 -0
- data/hobo_files/plugin/lib/hobo/undefined.rb +3 -2
- data/hobo_files/plugin/lib/hobo/{authenticated_user.rb → user.rb} +10 -3
- data/hobo_files/plugin/lib/hobo/user_controller.rb +27 -23
- data/hobo_files/plugin/tags/core.dryml +8 -2
- data/hobo_files/plugin/tags/rapid.dryml +52 -40
- data/hobo_files/plugin/tags/rapid_document_tags.dryml +15 -11
- data/hobo_files/plugin/tags/rapid_editing.dryml +41 -9
- data/hobo_files/plugin/tags/rapid_forms.dryml +136 -36
- data/hobo_files/plugin/tags/rapid_navigation.dryml +2 -2
- data/hobo_files/plugin/tags/rapid_pages.dryml +204 -221
- data/hobo_files/plugin/tags/rapid_plus.dryml +8 -6
- data/hobo_files/plugin/tags/rapid_support.dryml +2 -3
- metadata +44 -42
- data/hobo_files/plugin/lib/hobo/define_tags.rb +0 -56
- data/hobo_files/plugin/lib/hobo/http_parameters.rb +0 -225
@@ -14,41 +14,41 @@ module Hobo
|
|
14
14
|
|
15
15
|
VIEWLIB_DIR = "taglibs"
|
16
16
|
|
17
|
-
|
17
|
+
PAGINATE_FORMATS = [ Mime::HTML, Mime::ALL ]
|
18
18
|
|
19
19
|
class << self
|
20
20
|
|
21
21
|
def included(base)
|
22
|
-
base.
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
base.class_eval do
|
23
|
+
@auto_actions ||= {}
|
24
|
+
|
25
|
+
extend ClassMethods
|
26
|
+
helper_method :find_partial, :model, :current_user
|
27
|
+
before_filter :set_no_cache_headers
|
27
28
|
end
|
28
29
|
|
29
|
-
base.before_filter :set_no_cache_headers
|
30
|
-
|
31
30
|
Hobo::Controller.included_in_class(base)
|
32
31
|
end
|
33
32
|
|
34
33
|
def find_partial(klass, as)
|
35
|
-
find_model_template(klass, as, true)
|
34
|
+
find_model_template(klass, as, :is_parital => true)
|
36
35
|
end
|
37
36
|
|
38
37
|
|
39
38
|
def template_path(dir, name, is_partial)
|
40
39
|
fileRx = is_partial ? /^_#{name}\.[^.]+/ : /^#{name}\.[^.]+/
|
41
40
|
full_dir = "#{RAILS_ROOT}/app/views/#{dir}"
|
42
|
-
|
41
|
+
if File.exists?(full_dir) && Dir.entries(full_dir).grep(fileRx).any?
|
43
42
|
return "#{dir}/#{name}"
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
47
46
|
|
48
|
-
def find_model_template(klass, name,
|
47
|
+
def find_model_template(klass, name, options={})
|
49
48
|
while klass and klass != ActiveRecord::Base
|
50
49
|
dir = klass.name.underscore.pluralize
|
51
|
-
|
50
|
+
dir = File.join(options[:subsite], dir) if options[:subsite]
|
51
|
+
path = template_path(dir, name, options[:is_partial])
|
52
52
|
return path if path
|
53
53
|
|
54
54
|
klass = klass.superclass
|
@@ -56,33 +56,32 @@ module Hobo
|
|
56
56
|
nil
|
57
57
|
end
|
58
58
|
|
59
|
+
end
|
60
|
+
|
61
|
+
module ClassMethods
|
62
|
+
|
63
|
+
attr_writer :model
|
59
64
|
|
60
|
-
def add_collection_actions(
|
61
|
-
defined_methods =
|
65
|
+
def add_collection_actions(name)
|
66
|
+
defined_methods = instance_methods
|
62
67
|
|
63
68
|
show_collection_method = "show_#{name}".to_sym
|
64
|
-
|
65
|
-
|
69
|
+
if show_collection_method.not_in?(defined_methods) && include_action?(show_collection_method, true)
|
70
|
+
define_method show_collection_method do
|
66
71
|
hobo_show_collection(name)
|
67
|
-
end
|
72
|
+
end
|
68
73
|
end
|
69
74
|
|
70
|
-
if Hobo.simple_has_many_association?(
|
75
|
+
if Hobo.simple_has_many_association?(model.reflections[name])
|
71
76
|
new_method = "new_#{name.to_s.singularize}"
|
72
|
-
if new_method.not_in?(defined_methods)
|
73
|
-
|
77
|
+
if new_method.not_in?(defined_methods) && include_action?(new_method, true)
|
78
|
+
define_method new_method do
|
74
79
|
hobo_new_in_collection(name)
|
75
80
|
end
|
76
81
|
end
|
77
82
|
end
|
78
83
|
end
|
79
|
-
|
80
|
-
end
|
81
|
-
|
82
|
-
module ClassMethods
|
83
|
-
|
84
|
-
attr_writer :model
|
85
|
-
|
84
|
+
|
86
85
|
def web_methods
|
87
86
|
@web_methods ||= superclass.respond_to?(:web_methods) ? superclass.web_methods : []
|
88
87
|
end
|
@@ -91,6 +90,10 @@ module Hobo
|
|
91
90
|
@show_actions ||= superclass.respond_to?(:show_actions) ? superclass.show_actions : []
|
92
91
|
end
|
93
92
|
|
93
|
+
def index_actions
|
94
|
+
@index_actions ||= superclass.respond_to?(:index_actions) ? superclass.index_actions : []
|
95
|
+
end
|
96
|
+
|
94
97
|
def collections
|
95
98
|
# By default, all has_many associations are published
|
96
99
|
@collections ||= if superclass.respond_to?(:collections)
|
@@ -119,66 +122,99 @@ module Hobo
|
|
119
122
|
end
|
120
123
|
|
121
124
|
|
122
|
-
def web_method(web_name,
|
123
|
-
method_name ||= web_name
|
125
|
+
def web_method(web_name, options={}, &block)
|
124
126
|
web_methods << web_name.to_sym
|
125
|
-
|
127
|
+
method = options[:method] || web_name
|
128
|
+
got_block = block_given?
|
129
|
+
define_method web_name do
|
130
|
+
# Make sure we have a copy of the options - it is being mutated somewhere
|
131
|
+
opts = {}.merge(options)
|
132
|
+
@this = find_instance(opts) unless opts[:no_find]
|
133
|
+
permission_denied unless Hobo.can_call?(current_user, @this, method)
|
134
|
+
if got_block
|
135
|
+
instance_eval(&block)
|
136
|
+
else
|
137
|
+
@this.send(method)
|
138
|
+
end
|
139
|
+
hobo_ajax_response unless performed?
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
def auto_actions(*args)
|
145
|
+
# auto_actions is either an array - the actions to provide, or a hash: { :except => [...] }
|
146
|
+
@auto_actions = case args.first
|
147
|
+
when :all then args.extract_options!
|
148
|
+
when :none then []
|
149
|
+
else args
|
150
|
+
end
|
151
|
+
|
152
|
+
self.class_eval do
|
153
|
+
def index; hobo_index end if include_action?(:index)
|
154
|
+
def show; hobo_show end if include_action?(:show)
|
155
|
+
def new; hobo_new end if include_action?(:new)
|
156
|
+
def create; hobo_create end if include_action?(:create)
|
157
|
+
def edit; hobo_edit end if include_action?(:edit)
|
158
|
+
def update; hobo_update end if include_action?(:update)
|
159
|
+
def destroy; hobo_destroy end if include_action?(:destroy)
|
160
|
+
|
161
|
+
def completions; hobo_completions end if include_action?(:completions)
|
162
|
+
|
163
|
+
collections.each { |c| add_collection_actions(c.to_sym) }
|
164
|
+
end
|
126
165
|
end
|
127
166
|
|
128
167
|
|
129
|
-
def show_action(*names)
|
168
|
+
def show_action(*names, &block)
|
130
169
|
show_actions.concat(names)
|
131
170
|
for name in names
|
132
|
-
|
171
|
+
if block
|
172
|
+
define_method(name, &block)
|
173
|
+
else
|
174
|
+
define_method(name) { hobo_show }
|
175
|
+
end
|
133
176
|
end
|
134
177
|
end
|
135
178
|
|
179
|
+
def index_action(*names, &block)
|
180
|
+
index_actions.concat(names)
|
181
|
+
for name in names
|
182
|
+
if block
|
183
|
+
define_method(name, &block)
|
184
|
+
else
|
185
|
+
define_method(name) { hobo_index }
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
136
189
|
|
137
190
|
def publish_collection(*names)
|
138
191
|
collections.concat(names)
|
139
|
-
names.each {|n|
|
192
|
+
names.each {|n| add_collection_actions(n)}
|
140
193
|
end
|
141
194
|
|
142
195
|
|
143
|
-
def find_instance(id)
|
196
|
+
def find_instance(id, options={})
|
144
197
|
if model.id_name? and id !~ /^\d+$/
|
145
|
-
model.find_by_id_name(id)
|
198
|
+
model.find_by_id_name(id, options)
|
146
199
|
else
|
147
|
-
model.find(id)
|
200
|
+
model.find(id, options)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def include_action?(name, collection_action=false)
|
205
|
+
name = name.to_sym
|
206
|
+
if @auto_actions.is_a?(Array)
|
207
|
+
# White list
|
208
|
+
name.in?(@auto_actions) || (collection_action && :collections.in?(@auto_actions))
|
209
|
+
else
|
210
|
+
# Black list
|
211
|
+
except = Array(@auto_actions[:except])
|
212
|
+
name.not_in?(except) || (collection_action && :collections.not_in?(except))
|
148
213
|
end
|
149
214
|
end
|
150
215
|
|
151
216
|
end
|
152
217
|
|
153
|
-
include HttpParameters
|
154
|
-
|
155
|
-
# --- ACTIONS --- #
|
156
|
-
|
157
|
-
def index; hobo_index; end
|
158
|
-
def show; hobo_show; end
|
159
|
-
def new; hobo_new; end
|
160
|
-
def create; hobo_create; end
|
161
|
-
def edit; hobo_edit; end
|
162
|
-
def update; hobo_update; end
|
163
|
-
def destroy; hobo_destroy; end
|
164
|
-
|
165
|
-
def completions
|
166
|
-
opts = self.class.autocompleter(params[:for])
|
167
|
-
if opts
|
168
|
-
# Eval any defined filters
|
169
|
-
instance_eval(&opts[:data_filters_block]) if opts[:data_filters_block]
|
170
|
-
conditions = data_filter_conditions
|
171
|
-
q = params[:query]
|
172
|
-
items = model.find(:all) { all?(send("#{attr}_contains", q), conditions && block(conditions)) }
|
173
|
-
|
174
|
-
render :text => "<ul>\n" + items.map {|i| "<li>#{i.send(attr)}</li>\n"}.join + "</ul>"
|
175
|
-
else
|
176
|
-
render :text => "No completer for #{attr}", :status => 404
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
|
181
|
-
# --- END OF ACTIONS --- #
|
182
218
|
|
183
219
|
protected
|
184
220
|
|
@@ -187,51 +223,65 @@ module Hobo
|
|
187
223
|
@data_filters[name] = b
|
188
224
|
end
|
189
225
|
|
190
|
-
def search(*
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
226
|
+
def search(*args)
|
227
|
+
if args.first.is_a?(Class)
|
228
|
+
model, search_string, *columns = args
|
229
|
+
else
|
230
|
+
model = self.model
|
231
|
+
search_string, *columns = args
|
232
|
+
end
|
233
|
+
return nil if search_string.blank?
|
234
|
+
|
235
|
+
model.conditions do
|
236
|
+
words = search_string.split
|
237
|
+
terms = words.map do |word|
|
238
|
+
cols = columns.map do |c|
|
239
|
+
if c.is_a?(Symbol)
|
240
|
+
send("#{c}_contains", word)
|
241
|
+
elsif c.is_a?(Hash)
|
242
|
+
c.map do |k, v|
|
243
|
+
related = send(k)
|
244
|
+
v = [v] unless v.is_a?(Array)
|
245
|
+
v.map { |related_col| related.send("#{related_col}_contains", word) }
|
246
|
+
end
|
200
247
|
end
|
201
|
-
end
|
202
|
-
|
203
|
-
|
248
|
+
end.flatten
|
249
|
+
any?(*cols)
|
250
|
+
end
|
251
|
+
all?(*terms)
|
204
252
|
end
|
205
253
|
end
|
206
254
|
|
207
255
|
attr_accessor :data_filters
|
208
256
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
257
|
+
|
258
|
+
# --- Action implementation helpers --- #
|
259
|
+
|
260
|
+
def find_instance(*args)
|
261
|
+
options = args.extract_options!
|
262
|
+
res = self.class.find_instance(args.first || params[:id], options)
|
263
|
+
instance_variable_set("@#{model.name.underscore}", res)
|
264
|
+
res
|
217
265
|
end
|
218
266
|
|
219
|
-
# --- action implementations --- #
|
220
267
|
|
221
|
-
def
|
222
|
-
|
223
|
-
|
224
|
-
@this = options[:collection] || paginated_find(options)
|
268
|
+
def set_named_this!
|
269
|
+
instance_variable_set("@#{@this.class.name.underscore}", @this)
|
270
|
+
end
|
225
271
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
272
|
+
|
273
|
+
def response_block(&b)
|
274
|
+
if b
|
275
|
+
if b.arity == 1
|
276
|
+
respond_to {|wants| yield(wants) }
|
277
|
+
else
|
278
|
+
yield
|
279
|
+
end
|
280
|
+
performed?
|
231
281
|
end
|
232
282
|
end
|
233
|
-
|
234
283
|
|
284
|
+
|
235
285
|
def paginated_find(*args, &b)
|
236
286
|
options = args.extract_options!
|
237
287
|
filter_conditions = data_filter_conditions
|
@@ -242,33 +292,39 @@ module Hobo
|
|
242
292
|
end
|
243
293
|
|
244
294
|
@association = options.delete(:association) ||
|
245
|
-
if args.
|
295
|
+
if args.length == 1
|
296
|
+
scopes = args.first
|
297
|
+
@association = scopes.to_s.split(".").inject(model) { |m, name| m.send(name) }
|
298
|
+
elsif args.length == 2
|
246
299
|
owner, collection_name = args
|
247
300
|
@association = collection_name.to_s.split(".").inject(owner) { |m, name| m.send(name) }
|
248
301
|
end
|
249
302
|
@reflection = @association.proxy_reflection if @association._?.respond_to?(:proxy_reflection)
|
250
303
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
else
|
258
|
-
model.count(count_options, &conditions_proc)
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
puts total_number
|
263
|
-
|
304
|
+
model_or_assoc, @member_class = if @association
|
305
|
+
[@association, @association.member_class]
|
306
|
+
else
|
307
|
+
[model, model]
|
308
|
+
end
|
309
|
+
|
264
310
|
page_size = options.delete(:page_size) || 20
|
265
311
|
page = options.delete(:page) || params[:page]
|
266
|
-
|
312
|
+
|
313
|
+
paginate = options.fetch(:paginate, request.format.in?(PAGINATE_FORMATS))
|
314
|
+
options.delete(:paginate)
|
315
|
+
if paginate
|
316
|
+
total_number = options.delete(:total_number) ||
|
317
|
+
begin
|
318
|
+
# If there is a conditions block, it may depend on the includes
|
319
|
+
count_options = conditions_proc ? { :include => options[:include] } : {}
|
320
|
+
model_or_assoc.count(count_options, &conditions_proc)
|
321
|
+
end
|
322
|
+
|
323
|
+
@pages = ::ActionController::Pagination::Paginator.new(self, total_number, page_size, page)
|
267
324
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
}.merge(options)
|
325
|
+
options = options.reverse_merge(:limit => @pages.items_per_page,
|
326
|
+
:offset => @pages.current.offset)
|
327
|
+
end
|
272
328
|
|
273
329
|
unless options.has_key?(:order)
|
274
330
|
_, desc, field = *params[:sort]._?.match(/^(-)?([a-z_]+(?:\.[a-z_]+)?)$/)
|
@@ -277,307 +333,346 @@ module Hobo
|
|
277
333
|
@sort_direction = desc ? "desc" : "asc"
|
278
334
|
|
279
335
|
table, column = if field =~ /^(.*)\.(.*)$/
|
280
|
-
|
336
|
+
[$1.camelize.constantize.table_name, $2]
|
281
337
|
else
|
282
|
-
|
283
|
-
[sort_model.table_name, field]
|
338
|
+
[@member_class.table_name, field]
|
284
339
|
end
|
285
|
-
|
340
|
+
options[:order] = "#{table}.#{column} #{@sort_direction}"
|
286
341
|
elsif !@association
|
287
342
|
options[:order] = :default
|
288
343
|
end
|
289
344
|
end
|
290
345
|
|
291
|
-
|
292
|
-
|
346
|
+
model_or_assoc.find(:all, options, &conditions_proc)
|
347
|
+
end
|
348
|
+
|
349
|
+
|
350
|
+
def find_instance_or_not_found(this=nil)
|
351
|
+
begin
|
352
|
+
this || find_instance
|
353
|
+
rescue ActiveRecord::RecordNotFound
|
354
|
+
not_found
|
355
|
+
false
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
def save_and_set_status!(record, original=nil)
|
360
|
+
can = if record.new_record?
|
361
|
+
Hobo.can_create?(current_user, record)
|
362
|
+
else
|
363
|
+
Hobo.can_update?(current_user, original, record)
|
364
|
+
end
|
365
|
+
status = if can
|
366
|
+
record.save ? :valid : :invalid
|
367
|
+
else
|
368
|
+
:not_allowed
|
369
|
+
end
|
370
|
+
set_status(status)
|
371
|
+
end
|
372
|
+
|
373
|
+
def set_status(status)
|
374
|
+
@status = status
|
375
|
+
end
|
376
|
+
|
377
|
+
def invalid?; @status == :invalid; end
|
378
|
+
|
379
|
+
def valid?; @status == :valid; end
|
380
|
+
|
381
|
+
def not_allowed?; @status == :not_allowed; end
|
382
|
+
|
383
|
+
|
384
|
+
def re_render_form(default_action)
|
385
|
+
if params[:page_path]
|
386
|
+
controller, view = Controller.controller_and_view_for(params[:page_path])
|
387
|
+
hobo_render(view, model_for(controller))
|
293
388
|
else
|
294
|
-
|
389
|
+
hobo_render(default_action)
|
295
390
|
end
|
296
391
|
end
|
297
392
|
|
298
393
|
|
299
|
-
def
|
300
|
-
|
301
|
-
options[this_option] || find_instance
|
302
|
-
rescue ActiveRecord::RecordNotFound
|
303
|
-
nil
|
304
|
-
end
|
305
|
-
|
306
|
-
not_found unless x
|
307
|
-
x
|
394
|
+
def model_for(controller_name)
|
395
|
+
"#{controller_name.camelize}Controller".constantize.model
|
308
396
|
end
|
309
397
|
|
310
398
|
|
311
|
-
|
399
|
+
# --- Action implementations --- #
|
400
|
+
|
401
|
+
def hobo_index(*args, &b)
|
402
|
+
options = args.extract_options!
|
403
|
+
options = LazyHash.new(options)
|
404
|
+
@model = model
|
405
|
+
collection = args.first
|
406
|
+
@this = if collection.blank?
|
407
|
+
paginated_find(options)
|
408
|
+
elsif collection.is_a?(String, Symbol)
|
409
|
+
paginated_find(collection, options) # a scope name
|
410
|
+
else
|
411
|
+
collection
|
412
|
+
end
|
413
|
+
instance_variable_set("@#{@model.name.pluralize.underscore}", @this)
|
414
|
+
response_block(&b) or hobo_render
|
415
|
+
end
|
416
|
+
|
417
|
+
|
418
|
+
def hobo_show(*args, &b)
|
419
|
+
options = args.extract_options!
|
312
420
|
options = LazyHash.new(options)
|
313
421
|
|
314
|
-
@this = find_instance_or_not_found(
|
315
|
-
|
316
|
-
|
422
|
+
@this = find_instance_or_not_found(args.first) and
|
423
|
+
begin
|
424
|
+
set_status(:not_allowed) unless Hobo.can_view?(current_user, @this)
|
317
425
|
set_named_this!
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
426
|
+
response_block(&b) or
|
427
|
+
if not_allowed?
|
428
|
+
permission_denied
|
429
|
+
else
|
430
|
+
hobo_render
|
431
|
+
end
|
322
432
|
end
|
323
|
-
end
|
324
433
|
end
|
325
434
|
|
326
435
|
|
327
|
-
def hobo_new(
|
436
|
+
def hobo_new(*args, &b)
|
437
|
+
options = args.extract_options!
|
328
438
|
options = LazyHash.new(options)
|
329
|
-
@this =
|
330
|
-
@this.set_creator(current_user)
|
439
|
+
@this = args.first || model.new
|
440
|
+
@this.set_creator(current_user) if options.fetch(:set_creator, true)
|
331
441
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
442
|
+
set_status(:not_allowed) unless Hobo.can_create?(current_user, @this)
|
443
|
+
set_named_this!
|
444
|
+
response_block(&b) or
|
445
|
+
if not_allowed?
|
446
|
+
permission_denied
|
447
|
+
else
|
448
|
+
hobo_render
|
449
|
+
end
|
339
450
|
end
|
340
451
|
|
341
452
|
|
342
|
-
def hobo_create(
|
453
|
+
def hobo_create(*args, &b)
|
454
|
+
options = args.extract_options!
|
343
455
|
options = LazyHash.new(options)
|
344
456
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
status = secure_change_transaction { initialize_record(@this, attributes) }
|
359
|
-
permission_denied(options) and return if status == :not_allowed
|
360
|
-
valid = status == :valid
|
361
|
-
end
|
362
|
-
|
457
|
+
@this = args.first ||
|
458
|
+
begin
|
459
|
+
create_model = if 'type'.in?(model.column_names) &&
|
460
|
+
(type_attr = params['type']) &&
|
461
|
+
type_attr.in?(model.send(:subclasses).every(:name))
|
462
|
+
type_attr.constantize
|
463
|
+
else
|
464
|
+
model
|
465
|
+
end
|
466
|
+
create_model.new(params[model.name.underscore])
|
467
|
+
end
|
468
|
+
@this.set_creator(current_user) if options.fetch(:set_creator, true)
|
469
|
+
save_and_set_status!(@this)
|
363
470
|
set_named_this!
|
364
471
|
|
365
|
-
if valid
|
366
|
-
|
367
|
-
|
368
|
-
|
472
|
+
flash[:notice] = "The #{model.name.titleize.downcase} was created successfully" if !request.xhr? && valid?
|
473
|
+
|
474
|
+
response_block(&b) or
|
475
|
+
if valid?
|
369
476
|
respond_to do |wants|
|
370
|
-
wants.html {
|
371
|
-
wants.js {
|
477
|
+
wants.html { redirect_to(params[:after_submit] || object_url(@this)) }
|
478
|
+
wants.js { hobo_ajax_response || render(:text => "") }
|
372
479
|
end
|
373
|
-
|
374
|
-
else
|
375
|
-
# Validation errors
|
376
|
-
unless options[:invalid_response]
|
480
|
+
elsif invalid?
|
377
481
|
respond_to do |wants|
|
378
|
-
wants.html {
|
379
|
-
wants.js
|
380
|
-
|
381
|
-
|
382
|
-
:text => ("There was a problem creating that #{create_model.name}.\n" +
|
383
|
-
@this.errors.full_messages.join("\n"))))
|
384
|
-
end
|
482
|
+
wants.html { re_render_form(:new) }
|
483
|
+
wants.js { render(:status => 500,
|
484
|
+
:text => ("There was a problem creating that #{create_model.name}.\n" +
|
485
|
+
@this.errors.full_messages.join("\n"))) }
|
385
486
|
end
|
487
|
+
elsif not_allowed?
|
488
|
+
permission_denied
|
386
489
|
end
|
387
|
-
end
|
388
490
|
end
|
389
491
|
|
390
|
-
|
391
|
-
def hobo_edit(
|
392
|
-
hobo_show(
|
393
|
-
end
|
492
|
+
|
493
|
+
def hobo_edit(*args, &b)
|
494
|
+
hobo_show(*args, &b)
|
495
|
+
end
|
394
496
|
|
395
497
|
|
396
|
-
def hobo_update(
|
498
|
+
def hobo_update(*args, &b)
|
499
|
+
options = args.extract_options!
|
397
500
|
options = LazyHash.new(options)
|
398
501
|
|
399
|
-
@this = find_instance_or_not_found(
|
400
|
-
|
502
|
+
@this = find_instance_or_not_found(args.first) or return
|
503
|
+
original = @this.duplicate
|
504
|
+
# 'duplicate' can cause these to be set, but they can conflict
|
505
|
+
# with the changes so we clear them
|
506
|
+
@this.send(:clear_aggregation_cache)
|
507
|
+
@this.send(:clear_association_cache)
|
401
508
|
|
402
509
|
changes = params[model.name.underscore]
|
403
|
-
|
510
|
+
@this.attributes = changes
|
511
|
+
save_and_set_status!(@this, original)
|
512
|
+
|
513
|
+
# Ensure current_user isn't out of date
|
514
|
+
@current_user = @this if @this == current_user
|
515
|
+
|
516
|
+
flash[:notice] = "Changes to the #{model.name.titleize.downcase} were saved" if !request.xhr? && valid?
|
404
517
|
|
405
518
|
set_named_this!
|
406
|
-
|
407
|
-
|
408
|
-
permission_denied(options)
|
409
|
-
return
|
410
|
-
|
411
|
-
when :valid
|
412
|
-
# Ensure current_user isn't out of date
|
413
|
-
@current_user = @this if @this == current_user
|
414
|
-
|
415
|
-
if block_given?
|
416
|
-
yield
|
417
|
-
else
|
519
|
+
response_block(&b) or
|
520
|
+
if valid?
|
418
521
|
respond_to do |wants|
|
419
522
|
wants.html do
|
420
|
-
|
523
|
+
redirect_to(params[:after_submit] || object_url(@this))
|
421
524
|
end
|
422
|
-
|
423
525
|
wants.js do
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
hobo_ajax_response(@this)
|
433
|
-
end
|
434
|
-
|
435
|
-
# Maybe no ajax requests were made
|
436
|
-
render :nothing => true unless performed?
|
526
|
+
if changes.size == 1
|
527
|
+
# Decreasingly hacky support for the scriptaculous in-place-editor
|
528
|
+
new_val = Hobo::Dryml.render_tag(@template, "view",
|
529
|
+
:with => @this, :field => changes.keys.first,
|
530
|
+
:no_wrapper => true)
|
531
|
+
hobo_ajax_response(@this, :new_field_value => new_val)
|
532
|
+
else
|
533
|
+
hobo_ajax_response(@this)
|
437
534
|
end
|
535
|
+
|
536
|
+
# Maybe no ajax requests were made
|
537
|
+
render :nothing => true unless performed?
|
438
538
|
end
|
439
539
|
end
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
overridable_response(options, :invalid_html_response) || render(:action => :edit)
|
447
|
-
end
|
448
|
-
|
449
|
-
wants.js do
|
450
|
-
overridable_response(options, :invalid_js_response) do
|
451
|
-
render(:status => 500,
|
452
|
-
:text => ("There was a problem with that change.\n" +
|
453
|
-
@this.errors.full_messages.join("\n")))
|
454
|
-
end
|
540
|
+
elsif invalid?
|
541
|
+
respond_to do |wants|
|
542
|
+
wants.html { re_render_form(:edit) }
|
543
|
+
wants.js { render(:status => 500,
|
544
|
+
:text => ("There was a problem with that change.\n" +
|
545
|
+
@this.errors.full_messages.join("\n"))) }
|
455
546
|
end
|
547
|
+
elsif not_allowed?
|
548
|
+
permission_denied
|
456
549
|
end
|
457
|
-
end
|
458
550
|
end
|
459
551
|
|
460
552
|
|
461
|
-
def hobo_destroy(
|
553
|
+
def hobo_destroy(*args, &b)
|
554
|
+
options = args.extract_options!
|
462
555
|
options = LazyHash.new(options)
|
463
|
-
@this = find_instance_or_not_found(
|
464
|
-
return unless @this
|
556
|
+
@this = find_instance_or_not_found(args.first) or return
|
465
557
|
|
466
558
|
set_named_this!
|
467
|
-
permission_denied(options) and return unless Hobo.can_delete?(current_user, @this)
|
468
559
|
|
469
|
-
@this
|
560
|
+
set_status(Hobo.can_delete?(current_user, @this) ? :valid : :not_allowed)
|
561
|
+
unless not_allowed?
|
562
|
+
@this.destroy
|
563
|
+
flash[:notice] = "The #{model.name.titleize.downcase} was deleted" unless request.xhr?
|
564
|
+
end
|
470
565
|
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
566
|
+
response_block(&b) or
|
567
|
+
if not_allowed?
|
568
|
+
permission_denied
|
569
|
+
else
|
570
|
+
respond_to do |wants|
|
571
|
+
wants.html { redirect_to(:action => "index") }
|
572
|
+
wants.js { hobo_ajax_response || render(:text => "") }
|
573
|
+
end
|
477
574
|
end
|
478
|
-
end
|
479
575
|
end
|
480
576
|
|
481
|
-
|
577
|
+
|
578
|
+
def hobo_show_collection(collection, options={}, &b)
|
482
579
|
options = LazyHash.new(options)
|
483
580
|
|
484
|
-
@owner = find_instance_or_not_found(options
|
485
|
-
return unless @owner
|
581
|
+
@owner = find_instance_or_not_found(options[:owner]) or return
|
486
582
|
|
487
|
-
|
488
|
-
|
489
|
-
@
|
490
|
-
|
491
|
-
if block_given?
|
492
|
-
yield
|
493
|
-
else
|
494
|
-
hobo_render(params[:action]) or hobo_render(:show_collection, @reflection.klass)
|
495
|
-
end
|
583
|
+
if collection.is_a?(Array)
|
584
|
+
@this = collection
|
585
|
+
@reflection = collection.proxy_reflection if collection.respond_to?(:proxy_reflection)
|
496
586
|
else
|
497
|
-
|
587
|
+
toplevel_collection = collection.to_s.split(".").first
|
588
|
+
set_status(:not_allowed) unless Hobo.can_view?(current_user, @owner, toplevel_collection)
|
589
|
+
@this = paginated_find(@owner, collection, options) unless not_allowed?
|
498
590
|
end
|
591
|
+
|
592
|
+
response_block(&b) or
|
593
|
+
if not_allowed?
|
594
|
+
permission_denied
|
595
|
+
else
|
596
|
+
hobo_render(params[:action]) or (@reflection and hobo_render(:show_collection, @reflection.klass))
|
597
|
+
end
|
499
598
|
end
|
500
599
|
|
501
600
|
|
502
|
-
def hobo_new_in_collection(collection,
|
601
|
+
def hobo_new_in_collection(collection, *args, &b)
|
602
|
+
options = args.extract_options!
|
603
|
+
this = args.first
|
503
604
|
options = LazyHash.new(options)
|
504
|
-
@owner = find_instance_or_not_found(options, :owner)
|
505
|
-
return unless @owner
|
506
|
-
|
507
|
-
permission_denied(options) and return unless Hobo.can_view?(current_user, @owner, collection)
|
508
605
|
|
509
|
-
@
|
510
|
-
@
|
511
|
-
@this
|
606
|
+
@owner = find_instance_or_not_found(options[:owner]) or return
|
607
|
+
@association = collection.is_a?(Array) ? collection : @owner.send(collection)
|
608
|
+
@this = this || @association.new
|
609
|
+
set_named_this!
|
610
|
+
@this.set_creator(current_user) if options.fetch(:set_creator, true)
|
512
611
|
|
513
|
-
|
612
|
+
set_status(:not_allowed) unless Hobo.can_create?(current_user, @this)
|
514
613
|
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
614
|
+
response_block(&b) or
|
615
|
+
if not_allowed?
|
616
|
+
permission_denied
|
617
|
+
else
|
618
|
+
hobo_render("new_#{collection.to_s.singularize}") or hobo_render("new_in_collection", @this.class)
|
619
|
+
end
|
520
620
|
end
|
521
621
|
|
522
|
-
|
523
|
-
# --- end action implementations --- #
|
524
622
|
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
623
|
+
def hobo_completions
|
624
|
+
opts = self.class.autocompleter(params[:for])
|
625
|
+
if opts
|
626
|
+
# Eval any defined filters
|
627
|
+
instance_eval(&opts[:data_filters_block]) if opts[:data_filters_block]
|
628
|
+
conditions = data_filter_conditions
|
629
|
+
q = params[:query]
|
630
|
+
items = model.find(:all) { all?(send("#{attr}_contains", q), conditions && block(conditions)) }
|
631
|
+
|
632
|
+
render :text => "<ul>\n" + items.map {|i| "<li>#{i.send(attr)}</li>\n"}.join + "</ul>"
|
633
|
+
else
|
634
|
+
render :text => "No completer for #{attr}", :status => 404
|
635
|
+
end
|
530
636
|
end
|
531
637
|
|
532
|
-
#
|
638
|
+
#def hobo_create_in_collection(collection, options={}, &b)
|
639
|
+
# hobo_create do
|
640
|
+
# hobo_new_in_collection(collection, :this => @this, &b)
|
641
|
+
# end
|
642
|
+
#end
|
533
643
|
|
644
|
+
|
645
|
+
# --- Response helpers --- #
|
534
646
|
|
535
|
-
|
536
|
-
headers["Pragma"] = "no-cache"
|
537
|
-
#headers["Cache-Control"] = ["must-revalidate", "no-cache", "no-store"]
|
538
|
-
#headers["Cache-Control"] = "no-cache"
|
539
|
-
headers["Cache-Control"] = "no-store"
|
540
|
-
headers["Expires"] ='0'
|
541
|
-
end
|
542
|
-
|
543
|
-
|
647
|
+
|
544
648
|
def permission_denied(options={})
|
545
|
-
if
|
546
|
-
# do nothing (callback handled by LazyHash)
|
547
|
-
elsif respond_to? :permission_denied_response
|
649
|
+
if respond_to? :permission_denied_response
|
548
650
|
permission_denied_response
|
651
|
+
elsif render_tag("PermissionDeniedPage", { :with => @this }, :status => 403)
|
652
|
+
# cool
|
549
653
|
else
|
550
654
|
message = options[:message] || "Permission Denied"
|
551
655
|
render :text => message, :status => 403
|
552
656
|
end
|
553
657
|
end
|
554
658
|
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
elsif respond_to? :not_found_response
|
659
|
+
|
660
|
+
def not_found
|
661
|
+
if respond_to? :not_found_response
|
559
662
|
not_found_response
|
663
|
+
elsif render_tag("NotFoundPage", { :with => @this }, :status => 404)
|
664
|
+
# cool
|
560
665
|
else
|
561
|
-
render(:text => "
|
666
|
+
render(:text => "The page you requested cannot be found.", :status => 404)
|
562
667
|
end
|
563
668
|
end
|
564
|
-
|
565
|
-
def find_instance(id=nil)
|
566
|
-
res = self.class.find_instance(id || params[:id])
|
567
|
-
instance_variable_set("@#{model.name.underscore}", res)
|
568
|
-
res
|
569
|
-
end
|
570
669
|
|
571
|
-
def set_named_this!
|
572
|
-
instance_variable_set("@#{model.name.underscore}", @this)
|
573
|
-
end
|
574
|
-
|
575
670
|
|
576
671
|
def hobo_render(page_kind = nil, page_model=nil)
|
577
672
|
page_kind ||= params[:action].to_sym
|
578
673
|
page_model ||= model
|
579
674
|
|
580
|
-
template =
|
675
|
+
template = ModelController.find_model_template(page_model, page_kind, :subsite => subsite)
|
581
676
|
|
582
677
|
begin
|
583
678
|
if template
|
@@ -601,17 +696,25 @@ module Hobo
|
|
601
696
|
end
|
602
697
|
end
|
603
698
|
|
699
|
+
|
700
|
+
# --- filters --- #
|
701
|
+
|
702
|
+
def set_no_cache_headers
|
703
|
+
headers["Pragma"] = "no-cache"
|
704
|
+
#headers["Cache-Control"] = ["must-revalidate", "no-cache", "no-store"]
|
705
|
+
#headers["Cache-Control"] = "no-cache"
|
706
|
+
headers["Cache-Control"] = "no-store"
|
707
|
+
headers["Expires"] ='0'
|
708
|
+
end
|
709
|
+
|
710
|
+
# --- end filters --- #
|
711
|
+
|
604
712
|
|
605
713
|
def model
|
606
714
|
self.class.model
|
607
715
|
end
|
608
716
|
|
609
717
|
|
610
|
-
def find_template
|
611
|
-
Hobo::ModelController.find_model_template(model, params[:action])
|
612
|
-
end
|
613
|
-
|
614
|
-
|
615
718
|
def data_filter_conditions
|
616
719
|
active_filters = data_filters && (params.keys & data_filters.keys)
|
617
720
|
filters = data_filters
|
@@ -621,63 +724,6 @@ module Hobo
|
|
621
724
|
end unless active_filters.blank?
|
622
725
|
end
|
623
726
|
|
624
|
-
|
625
|
-
def XXupdate_with_params(object, params)
|
626
|
-
return unless params
|
627
|
-
|
628
|
-
params.each_pair do |field,value|
|
629
|
-
field = field.to_sym
|
630
|
-
refl = object.class.reflections[field]
|
631
|
-
is_has_many = refl && Hobo.simple_has_many_association?(refl)
|
632
|
-
|
633
|
-
if is_has_many
|
634
|
-
items = if value.is_a? Array
|
635
|
-
value.map {|x| associated_record(object, refl, x) }
|
636
|
-
else
|
637
|
-
value.keys.every(:to_i).sort.map{|i| associated_record(object, refl, value[i.to_s]) }
|
638
|
-
end
|
639
|
-
object.send(field).target[0..-1] = items
|
640
|
-
else
|
641
|
-
ar_value = if refl
|
642
|
-
if refl.macro == :belongs_to
|
643
|
-
associated_record(object, refl, value)
|
644
|
-
else
|
645
|
-
raise HoboError, "association #{object.class}.#{refl.name} is not settable via parameters"
|
646
|
-
end
|
647
|
-
else
|
648
|
-
param_to_value(object.class.field_type(field), value)
|
649
|
-
end
|
650
|
-
object.send("#{field}=".to_sym, ar_value)
|
651
|
-
end
|
652
|
-
end
|
653
|
-
end
|
654
|
-
|
655
|
-
|
656
|
-
def XXassociated_record(owner, refl, value)
|
657
|
-
if value.is_a? String
|
658
|
-
if value.starts_with?('@')
|
659
|
-
Hobo.object_from_dom_id(value[1..-1])
|
660
|
-
elsif refl.klass.id_name?
|
661
|
-
refl.klass.find_by_id_name(value)
|
662
|
-
else
|
663
|
-
nil
|
664
|
-
end
|
665
|
-
else
|
666
|
-
if refl.macro == :belongs_to
|
667
|
-
new_from_params(refl.klass, value)
|
668
|
-
else
|
669
|
-
obj = owner.send(refl.name).new
|
670
|
-
initialize_from_params(obj, value)
|
671
|
-
obj
|
672
|
-
end
|
673
|
-
end
|
674
|
-
end
|
675
|
-
|
676
|
-
|
677
|
-
def XXobject_from_param(param)
|
678
|
-
Hobo.object_from_dom_id(param)
|
679
|
-
end
|
680
|
-
|
681
727
|
end
|
682
728
|
|
683
729
|
end
|