hobo_rapid 1.4.0.pre6 → 1.4.0.pre7

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/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.0.pre6
1
+ 1.4.0.pre7
@@ -0,0 +1,37 @@
1
+ module HoboCacheHelper
2
+ def hobo_cache_key(namespace=:views, route_on=nil, query_params=nil, attributes=nil)
3
+ attributes ||= {}
4
+
5
+ if route_on == true
6
+ route_on = this
7
+ end
8
+
9
+ if route_on.is_a?(ActiveRecord::Base)
10
+ route_on = url_for(route_on)
11
+ end
12
+
13
+ if route_on
14
+ attributes.reverse_merge!(Rails.application.routes.recognize_path(route_on))
15
+ elsif params[:page_path]
16
+ # it's quite possible that our page was rendered by a different action, so normalize
17
+ attributes.reverse_merge!(Rails.application.routes.recognize_path(params[:page_path]))
18
+ end
19
+
20
+ key_attrs = attributes
21
+ key_attrs[:only_path] = false
22
+ comma_split(query_params || "").each do |qp|
23
+ key_attrs["#{qp}"] = params[qp] || ""
24
+ end
25
+
26
+ ActiveSupport::Cache.expand_cache_key(url_for(key_attrs).split('://').last, namespace)
27
+ end
28
+
29
+ def item_cache(*args, &block)
30
+ unless Rails.configuration.action_controller.perform_caching
31
+ yield if block_given?
32
+ else
33
+ key = hobo_cache_key(:item, *args)
34
+ Rails.cache.fetch(key, &block)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,10 @@
1
+ module HoboRapid
2
+ # this after_filter is useful for the after_submit tag
3
+ class PreviousUriFilter
4
+ def self.filter(controller)
5
+ if controller.request.get?
6
+ controller.session[:previous_uri] = controller.request.path
7
+ end
8
+ end
9
+ end
10
+ end
data/lib/hobo_rapid.rb CHANGED
@@ -1,3 +1,6 @@
1
+ ActiveSupport::Dependencies.autoload_paths |= [File.dirname(__FILE__)]
2
+ ActiveSupport::Dependencies.autoload_once_paths |= [File.dirname(__FILE__)]
3
+
1
4
  module HoboRapid
2
5
 
3
6
  VERSION = File.read(File.expand_path('../../VERSION', __FILE__)).strip
@@ -47,7 +47,12 @@ All the standard ajax attributes *except the callbacks* are supported (see the m
47
47
  in_place = !(this == @this && request.method.downcase == "get") if in_place.nil?
48
48
  update_attrs, attributes = attributes.partition_hash(HoboRapidHelper::AJAX_UPDATE_ATTRS)
49
49
  ajax_attrs, attributes = attributes.partition_hash(HoboRapidHelper::AJAX_ATTRS)
50
- attributes[src] = "#{base_url}/images/#{image}" if image
50
+ if image
51
+ attributes[:src] ||= image_path(image)
52
+ attributes[:type] ||= 'image'
53
+ else
54
+ attributes[:type] ||= 'submit'
55
+ end
51
56
  label ||= t("hobo.actions.remove", :default=>"Remove")
52
57
  confirm = t("hobo.messages.confirm", :default=>"Are you sure?") if confirm.nil?
53
58
  ajax_attrs[:confirm] = confirm if confirm
@@ -69,7 +74,7 @@ All the standard ajax attributes *except the callbacks* are supported (see the m
69
74
  %>
70
75
  <if test="&url && can_delete?">
71
76
  <form method="delete" action="&url" class="button_to" merge-attrs="&ajax_attrs" data-rapid="&data_rapid" data-rapid-context="&typed_id">
72
- <input type="submit" value="&label" merge/>
77
+ <input value="&label" merge/>
73
78
  </form>
74
79
  </if>
75
80
  </def>
@@ -1 +1,42 @@
1
1
  <!-- Tags for caching -->
2
+
3
+
4
+ <!-- `<cache>` is a simple fragment cache without the hierarchical dependency tracking used in `<swept-cache>` or `<nested-cache>`.
5
+
6
+ ### Attributes
7
+
8
+ All extra attributes are used as cache keys.
9
+
10
+ `query-params`: A comma separated list of query (or post) parameters
11
+ used as non-hierarchical cache keys.
12
+
13
+ `route-on`: Rails fragment caching uses the the current route to build
14
+ its cache key. If you are caching an item that will be used in
15
+ multiple different actions, you can specify route-on to ensure that
16
+ the different actions can share the cache. You can pass either an
17
+ object or a path to route-on. If you pass an object, it is converted
18
+ to a path with `url_for`. If you specify route-on without a value,
19
+ `this` is used. An alternative to using `route-on` is to specify
20
+ `controller`, `action` and any other required path parameters
21
+ explicitly. For example route-on="&posts_path" is identical to
22
+ controller="posts" action="index". If you do not specify route-on or
23
+ controller, action, etc., `params[:page_path]` or the current action
24
+ is used.
25
+
26
+ -->
27
+ <def tag="cache" attrs="query-params,route-on"><%
28
+ unless Rails.configuration.action_controller.perform_caching
29
+ %><%= parameters.default %><%
30
+ else
31
+ key_key_s = hobo_cache_key(:views, route_on, query_params, attributes)
32
+ cache_content = Rails.cache.read key_key_s
33
+ unless cache_content.nil?
34
+ Rails.logger.debug "CACHE HIT #{key_key_s}"
35
+ %><%= raw cache_content %><%
36
+ else
37
+ Rails.logger.debug "CACHE MISS #{key_key_s}"
38
+ %><%= raw cache_content=parameters.default %><%
39
+ Rails.cache.write(key_key_s, cache_content)
40
+ end
41
+ end
42
+ %></def>
@@ -59,7 +59,8 @@ replace with:
59
59
  ### Attributes
60
60
 
61
61
  All extra attributes are used as non-hierarchical cache keys, so for
62
- inner caches these should be constants.
62
+ inner caches these should either be constants or be manually
63
+ propagated to the outer caches
63
64
 
64
65
  `methods`: A comma separated list of methods or fields that can be
65
66
  called on the context (aka this) to produce cache keys. Example:
@@ -76,7 +77,7 @@ its cache key. If you are caching an item that will be used in
76
77
  multiple different actions, you can specify route-on to ensure that
77
78
  the different actions can share the cache. You can pass either an
78
79
  object or a path to route-on. If you pass an object, it is converted
79
- to a path with `url_for`. If you specify route-on with a value,
80
+ to a path with `url_for`. If you specify route-on without a value,
80
81
  `this` is used. An alternative to using `route-on` is to specify
81
82
  `controller`, `action` and any other required path parameters
82
83
  explicitly. For example route-on="&posts_path" is identical to
@@ -88,25 +89,13 @@ attribute.
88
89
 
89
90
  ### Hints
90
91
 
91
- If you are using an LRU cache such as memory-cache, memcached or redis
92
- you typically specify `updated_at` in the methods attribute.
92
+ If you have sweepers, you probably want `<swept-cache>` instead.
93
93
 
94
- If you are using a cache with manual expiration, `typed_id` is a
95
- convenient unique id that is available on all Hobo models that have
96
- been saved in the database. You can then add this to your FooSweeper:
97
-
98
- def after_update(foo)
99
- Rails.cache.delete_matched(/typed_id\=#{CGI.escape foo.typed_id}(&|$)/)
100
- end
101
-
102
- This will delete the fragment, along will all fragments that contain
103
- that fragment.
104
-
105
- Another thing to keep in mind is that any Hobo tag that can generate a
106
- page refresh, such as filter-menu, table-plus or page-nav stores query
107
- parameters such as search, sort & page so that these are not lost when
108
- refreshed. So they will need to be added to the query-params for any
109
- cache containing such tags.
94
+ Any Hobo tag that can generate a page refresh, such as filter-menu,
95
+ table-plus or page-nav stores query parameters such as search, sort &
96
+ page so that these are not lost when the tag is used to refresh the
97
+ page. These will need to be added to the query-params for any cache
98
+ containing such tags.
110
99
 
111
100
  -->
112
101
  <def tag="nested-cache" attrs="methods,query-params,route-on">
@@ -133,7 +122,7 @@ cache containing such tags.
133
122
  end
134
123
 
135
124
  comma_split(query_params).each do |qp|
136
- key_key["@#{qp}"] = params[qp]
125
+ key_key["@#{qp}"] = params[qp] || ""
137
126
  end
138
127
 
139
128
  if route_on == true
@@ -146,10 +135,8 @@ cache containing such tags.
146
135
 
147
136
  if route_on
148
137
  attributes.reverse_merge!(Rails.application.routes.recognize_path(route_on))
149
- end
150
-
151
- # it's quite possible that our page was rendered by a different action, so normalize
152
- if params[:page_path]
138
+ elsif params[:page_path]
139
+ # it's quite possible that our page was rendered by a different action, so normalize
153
140
  attributes.reverse_merge!(Rails.application.routes.recognize_path(params[:page_path]))
154
141
  end
155
142
 
@@ -247,7 +234,7 @@ cache containing such tags.
247
234
  fail if scope.cache_paths_stack.length>0
248
235
  end
249
236
  else
250
- # we have a parent cache, so it's set up the scope.
237
+ # we have a parent cache, so it has set up the scope.
251
238
  if form_field_path.nil? || form_field_path[0...scope.cache_path_root.length] != scope.cache_path_root
252
239
  fail "nested caching error: form_field_path has been corrupted via with= or form"
253
240
  end
@@ -303,9 +290,10 @@ cache containing such tags.
303
290
  thunk2.call(k,v,cache_keys[k])
304
291
  end
305
292
 
293
+ # if content_key_s has a value, it means that our original key is still valid, but we were invalidated by our children.
306
294
  if content_key_s.nil?
307
295
  if !have_children
308
- # if we don't have any children, then we can store the content against key_key_s. We also store cache_keys in case we ever have a parent who needs to regenerate their keys. We can give then them ours without regenerating.
296
+ # if we don't have any children, then we can store the content against key_key_s. We also store cache_keys in case we ever have a parent who needs to regenerate their keys. We can then give them ours without regenerating.
309
297
  Rails.logger.debug "CACHE: #{key_key_s} -> content + key #{cache_keys}"
310
298
  Rails.cache.write(key_key_s, [cache_content, cache_keys])
311
299
  content_key_s = ""
@@ -328,5 +316,4 @@ cache containing such tags.
328
316
 
329
317
  end
330
318
  end
331
- %>
332
- </def>
319
+ %></def>
@@ -0,0 +1,264 @@
1
+ <!--
2
+
3
+ `<swept-cache>` is a fragment cache that stores context dependency information for itself and all contained inner swept-cache's. Dependencies are not checked if the cache is hit. This means that swept-cache should be considerably faster than `<nested-cache>`, but it does require that you create sweepers for your caches. These sweepers can use the stored dependency information to invalidate the appropriate fragments.
4
+
5
+ ### Example
6
+
7
+ <def tag="card" for="Foo">
8
+ <swept-cache route-on suffix="card">
9
+ <card without-header>
10
+ <body:><view:body/></body>
11
+ </card>
12
+ </nested-cache>
13
+ </def>
14
+
15
+ <def tag="view" for="Bar">
16
+ <swept-cache route-on suffix="view">
17
+ <view:body/>
18
+ <swept-cache:foos route-on="&this_parent" suffix="collection">
19
+ <collection/>
20
+ <swept-cache>
21
+ </swept-cache>
22
+ </def>
23
+
24
+ class FooSweeper < ActionController::Caching::Sweeper
25
+ observe Foo
26
+
27
+ def after_create(foo)
28
+ expire_swept_caches_for(foo.bar, :foos)
29
+ end
30
+
31
+ def after_update(foo)
32
+ expire_swept_caches_for(foo)
33
+ expire_swept_caches_for(foo.bar, :foos)
34
+ end
35
+
36
+ def after_destroy(foo)
37
+ expire_swept_caches_for(foo)
38
+ expire_swept_caches_for(foo.bar, :foos)
39
+ end
40
+ end
41
+
42
+ class BarSweeper < ActionController::Caching::Sweeper
43
+ observe Bar
44
+
45
+ def after_update(bar)
46
+ expire_swept_caches_for(bar)
47
+ end
48
+
49
+ def after_destroy(bar)
50
+ expire_swept_caches_for(bar)
51
+ end
52
+ end
53
+
54
+ In the above example, if a Foo gets updated, the following fragment caches will be invalidated:
55
+
56
+ - the card for the foo
57
+ - the collection of foos inside bar
58
+ - the bar view
59
+ - any pages that have a swept-cache that contains a view of bar
60
+
61
+ When outer caches are rebuilt, inner caches that are still valid may be used as is.
62
+
63
+ ### Specifying the Context
64
+
65
+ swept-cache assumes that the cache is dependent on the current context
66
+ (aka this) as well as the context of any contained swept-cache's.
67
+
68
+ The context must be either an object that has been saved to the
69
+ database, or an attribute on an object that has been saved to the
70
+ database. If it is not one of these two, you must either switch the
71
+ context to something that is, or specify the dependencies manually.
72
+
73
+ When specifying the dependencies manually, you pass a list of database
74
+ objects, database objects plus an attribute name, and/or strings.
75
+
76
+ <swept-cache dependencies="&[this, [this, :comments], foo, :all_foos]"
77
+
78
+ Note that when dependencies are specified manually, `this` must be
79
+ added to the list, if so desired.
80
+
81
+ Also note that dependencies are not added to the cache key.
82
+
83
+ ### Attributes
84
+
85
+ All extra attributes are used as non-hierarchical cache keys, so for
86
+ inner caches these should either be constants or be manually
87
+ propagated to the outer caches
88
+
89
+ `dependencies`: see above. Default is "&[this]"
90
+
91
+ `query-params`: A comma separated list of query (or post) parameters
92
+ used as non-hierarchical cache keys.
93
+
94
+ `route-on`: Rails fragment caching uses the the current route to build
95
+ its cache key. If you are caching an item that will be used in
96
+ multiple different actions, you can specify route-on to ensure that
97
+ the different actions can share the cache. You can pass either an
98
+ object or a path to route-on. If you pass an object, it is converted
99
+ to a path with `url_for`. If you specify route-on without a value,
100
+ `this` is used. An alternative to using `route-on` is to specify
101
+ `controller`, `action` and any other required path parameters
102
+ explicitly. For example route-on="&posts_path" is identical to
103
+ controller="posts" action="index". If you do not specify route-on or
104
+ controller, action, etc., `params[:page_path]` or the current action
105
+ is used. route-on is a non-hierarchical key.
106
+
107
+ ### Hints
108
+
109
+ Any Hobo tag that can generate a page refresh, such as filter-menu,
110
+ table-plus or page-nav stores query parameters such as search, sort &
111
+ page so that these are not lost when the tag is used to refresh the
112
+ page. These will need to be added to the query-params for any cache
113
+ containing such tags.
114
+
115
+ ### Example: Caching @current_user
116
+
117
+ This is the pattern we use to cache the page header:
118
+
119
+ <swept-cache suffix="header" current-user="&@current_user.id" dependencies="&[@current_user]">
120
+
121
+ Notice that @current_user is specified as a dependency in 2 different ways.
122
+
123
+ `current-user="&@current_user.id"` ensures that the current user's ID
124
+ is added to the cache key, ensuring that each user gets their own
125
+ header rather than having every user share the same header.
126
+
127
+ `dependencies="&[@current_user]` does not affect the cache key, only
128
+ the cache content. It enables the cache to be swept if any of the user
129
+ columns change, such as the user's name.
130
+
131
+ ### Cache Store requirements
132
+
133
+ #### stability
134
+
135
+ For this tag to function correctly, the cache must not evict the
136
+ dependency information, so purely LRU caches such as MemoryStore may
137
+ not be used in production. The cache can evict fragments, though. For
138
+ this reason, you may configure two separate caches:
139
+
140
+ config.cache_store = :memory_store, {:size => 512.megabytes}
141
+ config.hobo.stable_cache_store = :file_store
142
+
143
+ Note that the dependency cache store does not have to be persistent,
144
+ it's OK to clear the dependency cache at the same time as the fragment
145
+ cache.
146
+
147
+ #### atomic updates
148
+
149
+ In production, swept-cache needs to be able to update a list
150
+ atomically. This is not an operation supported by the Rails cache API,
151
+ but it is supported by most non-trivial caches via one of several
152
+ mechanisms.
153
+
154
+ #### supported caches
155
+
156
+ memory_store: not compliant, but can be used for development if the size is set large enough to avoid evictions.
157
+
158
+ [file_store](http://api.rubyonrails.org/classes/ActiveSupport/Cache/FileStore.html): A good choice for low traffic sites where reads vastly outnumber writes.
159
+
160
+ memcached: not compliant
161
+
162
+ redis: a great choice. You can use the same instance for both fragment caching with expiry set the fragments to expire without disturbing the dependency information by setting the options differently:
163
+
164
+ config.cache_store = :redis_store, "redis://192.168.1.2:6379/1", :expires_in => 60.minutes
165
+ config.hobo.stable_cache_store = :redis_store, "redis://192.168.1.2:6379/1"
166
+
167
+ [torquebox infinispan](http://torquebox.org/): another great choice
168
+
169
+ config.cache_store = :torque_box_store
170
+ config.hobo.stable_cache_store = :torque_box_store, :name => 'dependencies', :mode => :replicated, :sync => true
171
+
172
+ others: ask on the hobo-users list.
173
+
174
+ -->
175
+ <def tag="swept-cache" attrs="query-params,route-on,dependencies"><%
176
+ unless Rails.configuration.action_controller.perform_caching
177
+ %><%= parameters.default %><%
178
+ else
179
+ key_key_s = hobo_cache_key(:views, route_on, query_params, attributes)
180
+ cache_content = Rails.cache.read key_key_s
181
+ unless cache_content.nil?
182
+ Rails.logger.debug "CACHE HIT #{key_key_s}"
183
+
184
+ cache_content, cache_ids = cache_content
185
+
186
+ if scope.cache_ids
187
+ # we have parent caches trying to generate their keys, so oblige them
188
+ scope.cache_ids += Set.new(cache_ids)
189
+ end
190
+
191
+ %><%= raw cache_content %><%
192
+ else
193
+ Rails.logger.debug "CACHE MISS #{key_key_s}"
194
+ # darn, cache is invalid. Now we have to generate our content and (re)generate our keys.
195
+
196
+ unless scope.cache_ids
197
+ # no parent caches so we need to set up the scope.
198
+ scope.new_scope(:cache_ids => Set.new, :cache_stack => []) do
199
+ %><%= cache_content=parameters.default %><%
200
+ cache_ids = scope.cache_ids
201
+ end
202
+ else
203
+ # we have a parent cache, so it has set up the scope.
204
+ scope.cache_stack.push scope.cache_ids
205
+ scope.cache_ids = Set.new
206
+ %><%= cache_content=parameters.default %><%
207
+ cache_ids = scope.cache_ids
208
+ end
209
+
210
+ dependencies = comma_split(dependencies) if dependencies.is_a?(String)
211
+ dependencies ||= [this]
212
+ dependencies.each do |dep|
213
+ if dep.respond_to?(:typed_id) && dep.typed_id
214
+ cache_ids << dep.typed_id
215
+ elsif dep.respond_to?(:origin) && dep.origin
216
+ cache_ids << "#{dep.origin.typed_id}:#{dep.origin_attribute}"
217
+ elsif dep.respond_to?(:to_sym)
218
+ cache_ids << dep.to_s
219
+ elsif dep.respond_to?(:first) && dep.first.respond_to?(:typed_id) && dep.first.typed_id && dep.last.respond_to?(:to_sym)
220
+ cache_ids << "#{dep.first.typed_id}:#{dep.last}"
221
+ else
222
+ fail "#{dep} not a Hobo model or not in database"
223
+ end
224
+ end
225
+
226
+ if scope.cache_stack
227
+ scope.cache_ids += scope.cache_stack.pop
228
+ end
229
+
230
+ cache_ids.each do |cache_id|
231
+ # the database we're using must support atomically adding to a cache key
232
+ # there are several possible ways of doing so.
233
+ # transactions: supported by Infinispan and activerecord-cache
234
+ # sets: Redis has a set datatype (SADD & friends)
235
+ # regex read: munge the value onto the key and then store that instead. Then do a regex read to get all values
236
+
237
+
238
+ if Hobo.stable_cache.respond_to?(:transaction)
239
+ key = ActiveSupport::Cache.expand_cache_key(cache_id, :sweep_key)
240
+ Hobo.stable_cache.transaction do
241
+ l = Set.new(Hobo.stable_cache.read(key)) << key_key_s
242
+ Rails.logger.debug "CACHE SWEEP KEY: #{cache_id} #{l.to_a}"
243
+ Hobo.stable_cache.write(key, l.to_a)
244
+ end
245
+ elsif Hobo.stable_cache.respond_to?(:read_matched)
246
+ key = ActiveSupport::Cache.expand_cache_key([cache_id, key_key_s], :sweep_key)
247
+ Rails.logger.debug "CACHE SWEEP KEY: #{key}"
248
+ Hobo.stable_cache.write(key, nil)
249
+ else
250
+ # TODO: add support for Redis
251
+ key = ActiveSupport::Cache.expand_cache_key(cache_id, :sweep_key)
252
+ Rails.logger.warn "WARNING! cache transactions not supported please fix before going to production"
253
+ l = Set.new(Hobo.stable_cache.read(key)) << key_key_s
254
+ Rails.logger.debug "CACHE SWEEP KEY: #{cache_id} #{l.to_a}"
255
+ Hobo.stable_cache.write(key, l.to_a)
256
+ end
257
+ end
258
+
259
+ # Also store cache_ids in case we ever have a parent who needs to regenerate their keys. We can give then them ours without regenerating.
260
+ Rails.logger.debug "CACHE: #{key_key_s} -> content + ids #{cache_ids.to_a}"
261
+ Rails.cache.write(key_key_s, [cache_content, cache_ids.to_a])
262
+ end
263
+ end
264
+ %></def>
data/taglibs/html/a.dryml CHANGED
@@ -114,7 +114,7 @@ The standard AJAX attributes are supported.
114
114
  nil_view
115
115
  elsif action == "new"
116
116
  # Link to a new object form
117
- new_record = target.new
117
+ new_record = target.respond_to?(:build) ? target.build : target.new
118
118
  new_record.set_creator(current_user)
119
119
  href = object_url(target, "new", params._?.merge(:subsite => subsite))
120
120
 
@@ -139,7 +139,7 @@ Produces:
139
139
  </if>
140
140
  <else>
141
141
  <% field_tag ||= "view" %>
142
- <unless test="&this.empty? && !empty">
142
+ <unless test="&(this.nil? || this.empty?) && !empty">
143
143
  <%= element "table", attributes - attrs_for(:with_fields) do %>
144
144
  <thead if="&all_parameters[:thead] || fields" param>
145
145
  <tr param="field-heading-row">
@@ -10,19 +10,25 @@ Use the `stay-here` attribute to remain on the current page:
10
10
  ...
11
11
  </form>
12
12
 
13
- Use the `go-back` option to return to the page in `session[:previous_uri]`:
13
+ Use the `uri` option to specify a redirect location:
14
14
 
15
15
  <form>
16
- <after-submit go-back/>
16
+ <after-submit uri="/admin"/>
17
17
  ...
18
18
  </form>
19
19
 
20
- Use the `uri` option to specify a redirect location:
20
+ Use the `go-back` option to return to the page in `session[:previous_uri]`:
21
21
 
22
22
  <form>
23
- <after-submit uri="/admin"/>
23
+ <after-submit go-back/>
24
24
  ...
25
25
  </form>
26
+
27
+ Note that session[:previous_uri] isn't automatically populated. To
28
+ automatically populate it, add to application_controller.rb:
29
+
30
+ after_filter HoboRapid::PreviousUriFilter
31
+
26
32
  -->
27
33
  <def tag="after-submit" attrs="uri, stay-here, go-back"><%
28
34
  uri = "stay-here" if stay_here
@@ -48,7 +48,8 @@ If the context is a `has_many :through` association, the polymorphic `<collectio
48
48
  elsif no_edit_permission && no_edit == :skip
49
49
  ""
50
50
  else
51
- attrs = add_classes(attributes, type_id.dasherize, type_and_field.dasherize)
51
+ attrs = attributes
52
+ attrs = add_classes(attrs, type_id.dasherize, type_and_field.dasherize) unless type_id.nil? || type_and_field.nil?
52
53
  attrs[:name] ||= param_name_for_this
53
54
  attrs[:disabled] = true if no_edit_permission && no_edit == :disable
54
55
  the_input = if (refl = this_field_reflection)
@@ -66,7 +67,7 @@ If the context is a `has_many :through` association, the polymorphic `<collectio
66
67
  (call_polymorphic_tag('input', HoboFields.to_class(this_type::COLUMN_TYPE), attrs) if defined?(this_type::COLUMN_TYPE)) or
67
68
  raise Hobo::Error, ("No input tag for #{this_field}:#{this_type} (this=#{this.inspect})")
68
69
  end
69
- unless this_parent.errors[this_field].empty?
70
+ unless this_parent.nil? || this_parent.errors[this_field].empty?
70
71
  "<span class='field-with-errors'>#{the_input}</span>".html_safe
71
72
  else
72
73
  the_input
@@ -22,9 +22,9 @@ See [Filtering stories by status](/tutorials/agility#filtering_stories_by_status
22
22
  Standard AJAX attributes such as 'update' are supported. If any are supplied, filter-menu uses Ajax rather than a page refresh.
23
23
 
24
24
  - `param-name` - the name of the HTTP parameter to use for the filter
25
- - `options` - an array of options or an array of arrays (useful for localized apps) for the menu.
26
- It can be omitted if you provide the options as an array or array of arrays in the locale file.
27
- - `no-filter` - The text of the first option which indicates no filter is in effect. Defaults to 'All'
25
+ - `options` - an array of options or an array of pairs (useful for localized apps) for the menu.
26
+ It can be omitted if you provide the options as an array or array of pairs in the locale file.
27
+ - `no-filter` - The text of the first option which indicates no filter is in effect. Defaults to 'All'. Pass "&false" to disable the no-filter option
28
28
  - `first-value` - the value to be used with the first option. Typically not used,
29
29
  meaning the option has a blank value.
30
30
  - model - the model name (optional: needed if you use the "activerecord.attributes" namespace.
@@ -85,11 +85,17 @@ or
85
85
  </select>
86
86
 
87
87
  -->
88
- <def tag="filter-menu" attrs="model, param-name, options, no-filter, id, first-value">
89
- <% options = t("activerecord.attributes.#{model}.filter_menu.#{param_name}.options", :default=>[:"tags.filter_menu.#{param_name}.options", options])
90
- raise ArgumentError, %(You must provide an "options" attribute, or set "activerecord.attributes.#{model}.filter_menu.#{param_name}.options" or "tags.filter_menu.#{param_name}.options" to an Array or to an Array of Arrays
91
- in your locale file(s)) unless options.is_a?(Array)
92
- no_filter = t("activerecord.attributes.#{model}.filter_menu.#{param_name}.no_filter", :default=>[:"tags.filter_menu.#{param_name}.no_filter", :"tags.filter_menu.default.no_filter", no_filter, "All"])
88
+ <def tag="filter-menu" attrs="model, param-name, options, no-filter, first-value">
89
+ <% # this odd construction is required in production mode for some reason
90
+ translated_options = I18n.translate("activerecord.attributes.#{model}.filter_menu.#{param_name}.options", :default=>[:"tags.filter_menu.#{param_name}.options"])
91
+ options = translated_options unless translated_options.is_a?(String)
92
+ raise ArgumentError, %(You must provide an "options" attribute, or set "activerecord.attributes.#{model}.filter_menu.#{param_name}.options" or "tags.filter_menu.#{param_name}.options" to an Array or to an Array of pairs in your locale file(s)) unless options.is_a?(Array)
93
+ if no_filter==false
94
+ no_filter = nil
95
+ else
96
+ no_filter = t("activerecord.attributes.#{model}.filter_menu.#{param_name}.no_filter", :default=>[:"tags.filter_menu.#{param_name}.no_filter", :"tags.filter_menu.default.no_filter", no_filter, "All"])
97
+ end
98
+ attributes['message'] ||= t("FIXME", :default => "Loading...") if HoboRapidHelper::AJAX_ATTRS.any?{|a| attributes.has_key?(a)}
93
99
  %>
94
100
  <form action="&request.path" method="get" class="filter-menu" merge-attrs="&attributes" data-rapid="&data_rapid('filter-menu')">
95
101
  <div>
@@ -0,0 +1,15 @@
1
+ <def tag="search-filter">
2
+ <form param="search-form" method="get" action="" with="&nil" merge-attrs >
3
+ <hidden-fields for-query-string skip="page, search"/>
4
+ <span param="label"><t key="hobo.table_plus.search">Search</t></span>
5
+ <input class="search" type="search" name="search" value="&params[:search]"/>
6
+ <submit label="&t('hobo.table_plus.submit_label', :default=>'Go')" class="search-button" param="search-submit"/>
7
+ </form>
8
+ <if test="&params[:search]">
9
+ <form param="clear-form" method="get" action="" merge-attrs>
10
+ <hidden-fields for-query-string skip="page, search"/>
11
+ <input type="hidden" name="search" value=""/>
12
+ <submit label="Clear" class="search-button" param="clear-submit"/>
13
+ </form>
14
+ </if>
15
+ </def>
@@ -26,12 +26,7 @@ sort-columns: a hash that allow you to map fields to sortable columns. The def
26
26
  <div class="table-plus" merge-attrs="&attributes - attrs_for(:with_fields) - attrs_for(:table)">
27
27
  <div class="header" param="header">
28
28
  <div class="search">
29
- <form param="search-form" method="get" action="" with="&nil" merge-attrs="&ajax_attrs" >
30
- <hidden-fields for-query-string skip="page, search"/>
31
- <span><t key="hobo.table_plus.search">Search</t></span>
32
- <input class="search" type="search" name="search" value="&params[:search]"/>
33
- <submit label="&t('hobo.table_plus.submit_label', :default=>'Go')" class="search-button" param="search-submit"/>
34
- </form>
29
+ <search-filter merge-attrs="&ajax_attrs" param/>
35
30
  </div>
36
31
  </div>
37
32
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: hobo_rapid
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: 6
5
- version: 1.4.0.pre6
5
+ version: 1.4.0.pre7
6
6
  platform: ruby
7
7
  authors:
8
8
  - Tom Locke, Bryan Larsen
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-04-24 00:00:00 Z
13
+ date: 2012-07-05 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: hobo
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - "="
22
22
  - !ruby/object:Gem::Version
23
- version: 1.4.0.pre6
23
+ version: 1.4.0.pre7
24
24
  type: :runtime
25
25
  version_requirements: *id001
26
26
  description: The RAPID tag library for Hobo
@@ -35,9 +35,11 @@ files:
35
35
  - README.markdown
36
36
  - VERSION
37
37
  - app/controllers/dev_controller.rb
38
+ - app/helpers/hobo_cache_helper.rb
38
39
  - app/helpers/hobo_rapid_helper.rb
39
40
  - hobo_rapid.gemspec
40
41
  - lib/hobo_rapid.rb
42
+ - lib/hobo_rapid/previous_uri_filter.rb
41
43
  - lib/hobo_rapid/railtie.rb
42
44
  - taglibs/buttons/buttons.dryml
43
45
  - taglibs/buttons/create_button.dryml
@@ -48,6 +50,7 @@ files:
48
50
  - taglibs/buttons/update_button.dryml
49
51
  - taglibs/cache/cache.dryml
50
52
  - taglibs/cache/nested_cache.dryml
53
+ - taglibs/cache/swept_cache.dryml
51
54
  - taglibs/cards/card.dryml
52
55
  - taglibs/cards/cards.dryml
53
56
  - taglibs/cards/search_card.dryml
@@ -122,6 +125,7 @@ files:
122
125
  - taglibs/plus/gravatar.dryml
123
126
  - taglibs/plus/live_search.dryml
124
127
  - taglibs/plus/plus.dryml
128
+ - taglibs/plus/search_filter.dryml
125
129
  - taglibs/plus/sortable_collection.dryml
126
130
  - taglibs/plus/table_plus.dryml
127
131
  - taglibs/views/a_or_an.dryml
@@ -165,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
169
  requirements: []
166
170
 
167
171
  rubyforge_project: hobo
168
- rubygems_version: 1.8.17
172
+ rubygems_version: 1.8.21
169
173
  signing_key:
170
174
  specification_version: 3
171
175
  summary: The RAPID tag library for Hobo