dry_crud 1.7.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +126 -87
  4. data/VERSION +1 -1
  5. data/lib/generators/dry_crud/dry_crud_generator.rb +42 -22
  6. data/lib/generators/dry_crud/templates/INSTALL +5 -5
  7. data/lib/generators/dry_crud/templates/app/assets/stylesheets/crud.scss +0 -20
  8. data/lib/generators/dry_crud/templates/app/assets/stylesheets/sample.scss +24 -4
  9. data/lib/generators/dry_crud/templates/app/controllers/crud/generic_model.rb +89 -0
  10. data/lib/generators/dry_crud/templates/app/controllers/crud/nestable.rb +70 -0
  11. data/lib/generators/dry_crud/templates/app/controllers/crud/rememberable.rb +64 -0
  12. data/lib/generators/dry_crud/templates/app/controllers/crud/render_callbacks.rb +46 -0
  13. data/lib/generators/dry_crud/templates/app/controllers/crud/responder.rb +31 -0
  14. data/lib/generators/dry_crud/templates/app/controllers/crud/searchable.rb +55 -0
  15. data/lib/generators/dry_crud/templates/app/controllers/crud/sortable.rb +63 -0
  16. data/lib/generators/dry_crud/templates/app/controllers/crud_controller.rb +66 -69
  17. data/lib/generators/dry_crud/templates/app/controllers/list_controller.rb +23 -326
  18. data/lib/generators/dry_crud/templates/app/helpers/actions_helper.rb +64 -0
  19. data/lib/generators/dry_crud/templates/app/helpers/crud/form_builder.rb +331 -0
  20. data/lib/generators/dry_crud/templates/app/helpers/crud/table_builder.rb +280 -0
  21. data/lib/generators/dry_crud/templates/app/helpers/form_helper.rb +52 -0
  22. data/lib/generators/dry_crud/templates/app/helpers/format_helper.rb +164 -0
  23. data/lib/generators/dry_crud/templates/app/helpers/i18n_helper.rb +85 -0
  24. data/lib/generators/dry_crud/templates/app/helpers/table_helper.rb +83 -0
  25. data/lib/generators/dry_crud/templates/app/helpers/utility_helper.rb +84 -0
  26. data/lib/generators/dry_crud/templates/app/views/crud/_actions_edit.html.erb +3 -3
  27. data/lib/generators/dry_crud/templates/app/views/crud/_actions_edit.html.haml +3 -3
  28. data/lib/generators/dry_crud/templates/app/views/crud/_actions_index.html.erb +1 -1
  29. data/lib/generators/dry_crud/templates/app/views/crud/_actions_index.html.haml +1 -1
  30. data/lib/generators/dry_crud/templates/app/views/crud/_actions_show.html.erb +3 -3
  31. data/lib/generators/dry_crud/templates/app/views/crud/_actions_show.html.haml +3 -3
  32. data/lib/generators/dry_crud/templates/app/views/crud/_attrs.html.erb +1 -1
  33. data/lib/generators/dry_crud/templates/app/views/crud/_attrs.html.haml +1 -1
  34. data/lib/generators/dry_crud/templates/app/views/crud/_form.html.erb +1 -1
  35. data/lib/generators/dry_crud/templates/app/views/crud/_form.html.haml +1 -1
  36. data/lib/generators/dry_crud/templates/app/views/crud/edit.html.erb +1 -1
  37. data/lib/generators/dry_crud/templates/app/views/crud/edit.html.haml +1 -1
  38. data/lib/generators/dry_crud/templates/app/views/crud/new.html.erb +2 -2
  39. data/lib/generators/dry_crud/templates/app/views/crud/new.html.haml +2 -2
  40. data/lib/generators/dry_crud/templates/app/views/crud/show.html.erb +1 -1
  41. data/lib/generators/dry_crud/templates/app/views/crud/show.html.haml +1 -1
  42. data/lib/generators/dry_crud/templates/app/views/layouts/_flash.html.haml +1 -1
  43. data/lib/generators/dry_crud/templates/app/views/layouts/_nav.html.erb +1 -1
  44. data/lib/generators/dry_crud/templates/app/views/layouts/_nav.html.haml +1 -1
  45. data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.erb +15 -7
  46. data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.haml +18 -8
  47. data/lib/generators/dry_crud/templates/app/views/list/_search.html.erb +3 -3
  48. data/lib/generators/dry_crud/templates/app/views/list/_search.html.haml +3 -3
  49. data/lib/generators/dry_crud/templates/app/views/list/index.html.erb +1 -1
  50. data/lib/generators/dry_crud/templates/app/views/list/index.html.haml +1 -1
  51. data/lib/generators/dry_crud/templates/app/views/shared/_error_messages.html.erb +1 -1
  52. data/lib/generators/dry_crud/templates/app/views/shared/_error_messages.html.haml +1 -1
  53. data/lib/generators/dry_crud/templates/app/views/shared/_labeled.html.erb +2 -4
  54. data/lib/generators/dry_crud/templates/app/views/shared/_labeled.html.haml +2 -3
  55. data/lib/generators/dry_crud/templates/config/initializers/field_error_proc.rb +5 -1
  56. data/lib/generators/dry_crud/templates/config/locales/crud.de.yml +64 -0
  57. data/lib/generators/dry_crud/templates/config/locales/{en_crud.yml → crud.en.yml} +2 -2
  58. data/lib/generators/dry_crud/templates/spec/controllers/crud_test_models_controller_spec.rb +241 -231
  59. data/lib/generators/dry_crud/templates/spec/helpers/crud/form_builder_spec.rb +226 -0
  60. data/lib/generators/dry_crud/templates/spec/helpers/{standard_table_builder_spec.rb → crud/table_builder_spec.rb} +36 -34
  61. data/lib/generators/dry_crud/templates/spec/helpers/form_helper_spec.rb +238 -0
  62. data/lib/generators/dry_crud/templates/spec/helpers/format_helper_spec.rb +244 -0
  63. data/lib/generators/dry_crud/templates/spec/helpers/i18n_helper_spec.rb +132 -0
  64. data/lib/generators/dry_crud/templates/spec/helpers/table_helper_spec.rb +265 -0
  65. data/lib/generators/dry_crud/templates/spec/helpers/utility_helper_spec.rb +74 -0
  66. data/lib/generators/dry_crud/templates/spec/support/crud_controller_examples.rb +185 -100
  67. data/lib/generators/dry_crud/templates/spec/support/crud_controller_test_helper.rb +58 -49
  68. data/lib/generators/dry_crud/templates/test/{functional → controllers}/crud_test_models_controller_test.rb +112 -91
  69. data/lib/generators/dry_crud/templates/test/{unit/helpers/standard_form_builder_test.rb → helpers/crud/form_builder_test.rb} +79 -62
  70. data/lib/generators/dry_crud/templates/test/{unit/helpers/standard_table_builder_test.rb → helpers/crud/table_builder_test.rb} +31 -28
  71. data/lib/generators/dry_crud/templates/test/helpers/custom_assertions_test.rb +85 -0
  72. data/lib/generators/dry_crud/templates/test/helpers/form_helper_test.rb +129 -0
  73. data/lib/generators/dry_crud/templates/test/helpers/format_helper_test.rb +163 -0
  74. data/lib/generators/dry_crud/templates/test/helpers/i18n_helper_test.rb +79 -0
  75. data/lib/generators/dry_crud/templates/test/helpers/table_helper_test.rb +217 -0
  76. data/lib/generators/dry_crud/templates/test/helpers/utility_helper_test.rb +63 -0
  77. data/lib/generators/dry_crud/templates/test/{functional → support}/crud_controller_test_helper.rb +70 -59
  78. data/lib/generators/dry_crud/templates/test/{crud_test_model.rb → support/crud_test_model.rb} +107 -75
  79. data/lib/generators/dry_crud/templates/test/support/custom_assertions.rb +83 -0
  80. metadata +83 -146
  81. data/Rakefile +0 -211
  82. data/lib/generators/dry_crud/templates/app/helpers/crud_helper.rb +0 -168
  83. data/lib/generators/dry_crud/templates/app/helpers/list_helper.rb +0 -27
  84. data/lib/generators/dry_crud/templates/app/helpers/standard_form_builder.rb +0 -261
  85. data/lib/generators/dry_crud/templates/app/helpers/standard_helper.rb +0 -304
  86. data/lib/generators/dry_crud/templates/app/helpers/standard_table_builder.rb +0 -178
  87. data/lib/generators/dry_crud/templates/spec/helpers/crud_helper_spec.rb +0 -146
  88. data/lib/generators/dry_crud/templates/spec/helpers/list_helper_spec.rb +0 -154
  89. data/lib/generators/dry_crud/templates/spec/helpers/standard_form_builder_spec.rb +0 -215
  90. data/lib/generators/dry_crud/templates/spec/helpers/standard_helper_spec.rb +0 -387
  91. data/lib/generators/dry_crud/templates/test/custom_assertions.rb +0 -78
  92. data/lib/generators/dry_crud/templates/test/unit/custom_assertions_test.rb +0 -117
  93. data/lib/generators/dry_crud/templates/test/unit/helpers/crud_helper_test.rb +0 -111
  94. data/lib/generators/dry_crud/templates/test/unit/helpers/list_helper_test.rb +0 -123
  95. data/lib/generators/dry_crud/templates/test/unit/helpers/standard_helper_test.rb +0 -281
  96. data/test/templates/Gemfile +0 -46
  97. data/test/templates/app/controllers/admin/cities_controller.rb +0 -7
  98. data/test/templates/app/controllers/admin/countries_controller.rb +0 -13
  99. data/test/templates/app/controllers/ajax_controller.rb +0 -9
  100. data/test/templates/app/controllers/people_controller.rb +0 -13
  101. data/test/templates/app/controllers/vips_controller.rb +0 -19
  102. data/test/templates/app/helpers/cities_helper.rb +0 -9
  103. data/test/templates/app/helpers/people_helper.rb +0 -8
  104. data/test/templates/app/models/city.rb +0 -28
  105. data/test/templates/app/models/country.rb +0 -16
  106. data/test/templates/app/models/person.rb +0 -12
  107. data/test/templates/app/views/admin/cities/_actions_index.html.erb +0 -2
  108. data/test/templates/app/views/admin/cities/_actions_index.html.haml +0 -2
  109. data/test/templates/app/views/admin/cities/_attrs.html.erb +0 -1
  110. data/test/templates/app/views/admin/cities/_attrs.html.haml +0 -1
  111. data/test/templates/app/views/admin/cities/_form.html.erb +0 -7
  112. data/test/templates/app/views/admin/cities/_form.html.haml +0 -5
  113. data/test/templates/app/views/admin/cities/_hello.html.erb +0 -1
  114. data/test/templates/app/views/admin/cities/_hello.html.haml +0 -1
  115. data/test/templates/app/views/admin/cities/_list.html.erb +0 -3
  116. data/test/templates/app/views/admin/cities/_list.html.haml +0 -3
  117. data/test/templates/app/views/admin/countries/_list.html.erb +0 -4
  118. data/test/templates/app/views/admin/countries/_list.html.haml +0 -3
  119. data/test/templates/app/views/ajax/_actions_index.html.erb +0 -8
  120. data/test/templates/app/views/ajax/_actions_index.html.haml +0 -8
  121. data/test/templates/app/views/ajax/_actions_show.html.erb +0 -4
  122. data/test/templates/app/views/ajax/_actions_show.html.haml +0 -4
  123. data/test/templates/app/views/ajax/_form.html.erb +0 -2
  124. data/test/templates/app/views/ajax/_form.html.haml +0 -2
  125. data/test/templates/app/views/ajax/_hello.html.erb +0 -1
  126. data/test/templates/app/views/ajax/_hello.html.haml +0 -1
  127. data/test/templates/app/views/ajax/ajax.js.erb +0 -1
  128. data/test/templates/app/views/ajax/ajax.js.haml +0 -1
  129. data/test/templates/app/views/ajax/edit.js.erb +0 -1
  130. data/test/templates/app/views/ajax/edit.js.haml +0 -1
  131. data/test/templates/app/views/ajax/show.js.erb +0 -1
  132. data/test/templates/app/views/ajax/show.js.haml +0 -1
  133. data/test/templates/app/views/ajax/update.js.erb +0 -5
  134. data/test/templates/app/views/ajax/update.js.haml +0 -5
  135. data/test/templates/app/views/layouts/_nav.html.erb +0 -6
  136. data/test/templates/app/views/layouts/_nav.html.haml +0 -5
  137. data/test/templates/app/views/layouts/bootstrap.html.erb +0 -68
  138. data/test/templates/app/views/layouts/bootstrap.html.haml +0 -49
  139. data/test/templates/app/views/people/_attrs.html.erb +0 -5
  140. data/test/templates/app/views/people/_attrs.html.haml +0 -4
  141. data/test/templates/app/views/people/_list.html.erb +0 -1
  142. data/test/templates/app/views/people/_list.html.haml +0 -1
  143. data/test/templates/config/database.yml +0 -21
  144. data/test/templates/config/locales/en_cities.yml +0 -56
  145. data/test/templates/config/routes.rb +0 -32
  146. data/test/templates/db/migrate/20100511174904_create_people_and_cities.rb +0 -26
  147. data/test/templates/db/seeds.rb +0 -74
  148. data/test/templates/spec/controllers/admin/cities_controller_spec.rb +0 -74
  149. data/test/templates/spec/controllers/admin/countries_controller_spec.rb +0 -56
  150. data/test/templates/spec/controllers/people_controller_spec.rb +0 -80
  151. data/test/templates/spec/routing/cities_routing_spec.rb +0 -11
  152. data/test/templates/spec/routing/countries_routing_spec.rb +0 -11
  153. data/test/templates/test/fixtures/cities.yml +0 -11
  154. data/test/templates/test/fixtures/countries.yml +0 -11
  155. data/test/templates/test/fixtures/people.yml +0 -14
  156. data/test/templates/test/functional/admin/cities_controller_test.rb +0 -59
  157. data/test/templates/test/functional/admin/countries_controller_test.rb +0 -42
  158. data/test/templates/test/functional/people_controller_test.rb +0 -68
@@ -1,304 +0,0 @@
1
- # A view helper to standartize often used functions like formatting,
2
- # tables, forms or action links. This helper is ideally defined in the
3
- # ApplicationController.
4
- module StandardHelper
5
-
6
- EMPTY_STRING = " ".html_safe # non-breaking space asserts better css styling.
7
-
8
- ################ FORMATTING HELPERS ##################################
9
-
10
- # Formats a single value
11
- def f(value)
12
- case value
13
- when Fixnum then number_with_delimiter(value)
14
- when Float, BigDecimal then number_with_precision(value, :precision => t('number.format.precision'),
15
- :delimiter => t('number.format.delimiter'))
16
- when Date then l(value)
17
- when Time then l(value, :format => :time)
18
- when true then t(:"global.yes")
19
- when false then t(:"global.no")
20
- when nil then EMPTY_STRING
21
- else value.to_s
22
- end
23
- end
24
-
25
- # Formats an arbitrary attribute of the given ActiveRecord object.
26
- # If no specific format_{type}_{attr} or format_{attr} method is found,
27
- # formats the value as follows:
28
- # If the value is an associated model, renders the label of this object.
29
- # Otherwise, calls format_type.
30
- def format_attr(obj, attr)
31
- format_type_attr_method = obj.class.respond_to?(:model_name) ? :"format_#{obj.class.model_name.underscore}_#{attr.to_s}" : :"format_#{obj.class.name.underscore}_#{attr.to_s}"
32
- format_attr_method = :"format_#{attr.to_s}"
33
- if respond_to?(format_type_attr_method)
34
- send(format_type_attr_method, obj)
35
- elsif respond_to?(format_attr_method)
36
- send(format_attr_method, obj)
37
- elsif assoc = association(obj, attr, :belongs_to)
38
- format_assoc(obj, assoc)
39
- elsif assoc = association(obj, attr, :has_many, :has_and_belongs_to_many)
40
- format_many_assoc(obj, assoc)
41
- else
42
- format_type(obj, attr)
43
- end
44
- end
45
-
46
-
47
- ############## STANDARD HTML SECTIONS ############################
48
-
49
-
50
- # Renders an arbitrary content with the given label. Used for uniform presentation.
51
- def labeled(label, content = nil, &block)
52
- content = capture(&block) if block_given?
53
- render 'shared/labeled', :label => label, :content => content
54
- end
55
-
56
- # Transform the given text into a form as used by labels or table headers.
57
- def captionize(text, clazz = nil)
58
- text = text.to_s
59
- if clazz.respond_to?(:human_attribute_name)
60
- clazz.human_attribute_name(text.end_with?('_ids') ? text[0..-5].pluralize : text)
61
- else
62
- text.humanize.titleize
63
- end
64
- end
65
-
66
- # Renders a list of attributes with label and value for a given object.
67
- # Optionally surrounded with a div.
68
- def render_attrs(obj, *attrs)
69
- safe_join(attrs) { |a| labeled_attr(obj, a) }
70
- end
71
-
72
- # Renders the formatted content of the given attribute with a label.
73
- def labeled_attr(obj, attr)
74
- labeled(captionize(attr, obj.class), format_attr(obj, attr))
75
- end
76
-
77
- # Renders a table for the given entries. One column is rendered for each attribute passed.
78
- # If a block is given, the columns defined therein are appended to the attribute columns.
79
- # If entries is empty, an appropriate message is rendered.
80
- # An options hash may be given as the last argument.
81
- def table(entries, *attrs, &block)
82
- entries.inspect # force evaluation of relations
83
- if entries.present?
84
- StandardTableBuilder.table(entries, self, attrs.extract_options!) do |t|
85
- t.attrs(*attrs)
86
- yield t if block_given?
87
- end
88
- else
89
- content_tag(:div, ti(:no_list_entries), :class => 'table')
90
- end
91
- end
92
-
93
- # Renders a standard form using StandardFormBuilder.
94
- # Before the input fields, the error messages are rendered, if present.
95
- def standard_form(object, options = {}, &block)
96
- options[:builder] ||= StandardFormBuilder
97
- options[:html] ||= {}
98
- add_css_class options[:html], 'form-horizontal'
99
-
100
- form_for(object, options) do |form|
101
- content = form.error_messages
102
- content << capture(form, &block)
103
- end
104
- end
105
-
106
- # Renders a simple unordered list, which will
107
- # simply render all passed items or yield them
108
- # to your block.
109
- def simple_list(items,ul_options={},&blk)
110
- content_tag_nested(:ul, items, ul_options) do |item|
111
- content_tag(:li, block_given? ? yield(item) : f(item))
112
- end
113
- end
114
-
115
- # render a content tag with the collected contents rendered
116
- # by &block for each item in collection.
117
- def content_tag_nested(tag, collection, options = {}, &block)
118
- content_tag(tag, safe_join(collection, &block), options)
119
- end
120
-
121
- # Overridden method that takes a block that is executed for each item in array
122
- # before appending the results.
123
- def safe_join(array, sep = $,, &block)
124
- super(block_given? ? array.collect(&block) : array, sep)
125
- end
126
-
127
- ######## ACTION LINKS ###################################################### :nodoc:
128
-
129
- # A generic helper method to create action links.
130
- # These link could be styled to look like buttons, for example.
131
- def link_action(label, icon = nil, url = {}, html_options = {})
132
- add_css_class html_options, 'action btn'
133
- link_to(icon ? action_icon(icon, label) : label,
134
- url, html_options)
135
- end
136
-
137
- # Outputs an icon for an action with an optional label.
138
- def action_icon(icon, label = nil)
139
- html = content_tag(:i, "", :class => "icon-#{icon}")
140
- html << ' ' << label if label
141
- html
142
- end
143
-
144
- # Translates the passed key by looking it up over the controller hierarchy.
145
- # The key is searched in the following order:
146
- # - {controller}.{current_partial}.{key}
147
- # - {controller}.{current_action}.{key}
148
- # - {controller}.global.{key}
149
- # - {parent_controller}.{current_partial}.{key}
150
- # - {parent_controller}.{current_action}.{key}
151
- # - {parent_controller}.global.{key}
152
- # - ...
153
- # - global.{key}
154
- def translate_inheritable(key, variables = {})
155
- defaults = []
156
- partial = @virtual_path ? @virtual_path.gsub(%r{.*/_?}, "") : nil
157
- current = controller.class
158
- while current < ActionController::Base
159
- folder = current.controller_path
160
- if folder.present?
161
- defaults << :"#{folder}.#{partial}.#{key}" if partial
162
- defaults << :"#{folder}.#{action_name}.#{key}"
163
- defaults << :"#{folder}.global.#{key}"
164
- end
165
- current = current.superclass
166
- end
167
- defaults << :"global.#{key}"
168
-
169
- variables[:default] ||= defaults
170
- t(defaults.shift, variables)
171
- end
172
-
173
- alias_method :ti, :translate_inheritable
174
-
175
- # Translates the passed key for an active record association. This helper is used
176
- # for rendering association dependent keys in forms like :no_entry, :none_available or
177
- # :please_select.
178
- # The key is looked up in the following order:
179
- # - activerecord.associations.models.{model_name}.{association_name}.{key}
180
- # - activerecord.associations.{association_model_name}.{key}
181
- # - global.associations.{key}
182
- def translate_association(key, assoc = nil, variables = {})
183
- primary = if assoc
184
- variables[:default] ||= [:"activerecord.associations.#{assoc.klass.model_name.underscore}.#{key}",
185
- :"global.associations.#{key}"]
186
- :"activerecord.associations.models.#{assoc.active_record.model_name.underscore}.#{assoc.name}.#{key}"
187
- else
188
- :"global.associations.#{key}"
189
- end
190
- t(primary, variables)
191
- end
192
-
193
- alias_method :ta, :translate_association
194
-
195
-
196
- # Returns the css class for the given flash level.
197
- def flash_class(level)
198
- case level
199
- when :notice then 'success'
200
- when :alert then 'error'
201
- else level.to_s
202
- end
203
- end
204
-
205
- # Adds a class to the given options, even if there are already classes.
206
- def add_css_class(options, classes)
207
- if options[:class]
208
- options[:class] += ' ' + classes
209
- else
210
- options[:class] = classes
211
- end
212
- end
213
-
214
- private
215
-
216
- # Helper methods that are not directly called from templates.
217
-
218
- # Formats an arbitrary attribute of the given object depending on its data type.
219
- # For ActiveRecords, take the defined data type into account for special types
220
- # that have no own object class.
221
- def format_type(obj, attr)
222
- val = obj.send(attr)
223
- return EMPTY_STRING if val.nil?
224
- case column_type(obj, attr)
225
- when :time then f(val.to_time)
226
- when :date then f(val.to_date)
227
- when :datetime, :timestamp then "#{f(val.to_date)} #{f(val.time)}"
228
- when :text then val.present? ? simple_format(h(val)) : EMPTY_STRING
229
- when :decimal then f(val.to_s.to_f)
230
- else f(val)
231
- end
232
- end
233
-
234
- # Returns the ActiveRecord column type or nil.
235
- def column_type(obj, attr)
236
- column_property(obj, attr, :type)
237
- end
238
-
239
- # Returns an ActiveRecord column property for the passed attr or nil
240
- def column_property(obj, attr, property)
241
- if obj.respond_to?(:column_for_attribute)
242
- column = obj.column_for_attribute(attr)
243
- column.try(property)
244
- end
245
- end
246
-
247
- # Formats an active record belongs_to association
248
- def format_assoc(obj, assoc)
249
- if val = obj.send(assoc.name)
250
- assoc_link(assoc, val)
251
- else
252
- ta(:no_entry, assoc)
253
- end
254
- end
255
-
256
- # Formats an active record has_and_belongs_to_many or
257
- # has_many association.
258
- def format_many_assoc(obj, assoc)
259
- values = obj.send(assoc.name)
260
- if values.size == 1
261
- assoc_link(assoc, values.first)
262
- elsif values.present?
263
- simple_list(values) { |val| assoc_link(assoc, val) }
264
- else
265
- ta(:no_entry, assoc)
266
- end
267
- end
268
-
269
- # Renders a link to the given association entry.
270
- def assoc_link(assoc, val)
271
- link_to_unless(no_assoc_link?(assoc, val), val.to_s, val)
272
- end
273
-
274
- # Returns true if no link should be created when formatting the given association.
275
- def no_assoc_link?(assoc, val)
276
- !respond_to?("#{val.class.model_name.underscore}_path".to_sym)
277
- end
278
-
279
- # Returns the association proxy for the given attribute. The attr parameter
280
- # may be the _id column or the association name. If a macro (e.g. :belongs_to)
281
- # is given, the association must be of this type, otherwise, any association
282
- # is returned. Returns nil if no association (or not of the given macro) was
283
- # found.
284
- def association(obj, attr, *macros)
285
- if obj.class.respond_to?(:reflect_on_association)
286
- name = assoc_and_id_attr(attr).first.to_sym
287
- assoc = obj.class.reflect_on_association(name)
288
- assoc if assoc && (macros.blank? || macros.include?(assoc.macro))
289
- end
290
- end
291
-
292
- # Returns the name of the attr and it's corresponding field
293
- def assoc_and_id_attr(attr)
294
- attr = attr.to_s
295
- attr, attr_id = if attr.end_with?('_id')
296
- [attr[0..-4], attr]
297
- elsif attr.end_with?('_ids')
298
- [attr[0..-5].pluralize, attr]
299
- else
300
- [attr, "#{attr}_id"]
301
- end
302
- end
303
-
304
- end
@@ -1,178 +0,0 @@
1
- # A simple helper to easily define tables listing several rows of the same data type.
2
- #
3
- # Example Usage:
4
- # StandardTableBuilder.table(entries, template) do |t|
5
- # t.col('My Header', :class => 'css') {|e| link_to 'Show', e }
6
- # t.attrs :name, :city
7
- # end
8
- class StandardTableBuilder
9
- attr_reader :entries, :cols, :options, :template
10
-
11
- # Delegate called methods to template.
12
- # including StandardHelper would lead to problems with indirectly called methods.
13
- delegate :content_tag, :format_attr, :column_type, :association, :dom_id,
14
- :captionize, :add_css_class, :content_tag_nested, :to => :template
15
-
16
- def initialize(entries, template, options = {})
17
- @entries = entries
18
- @template = template
19
- @options = options
20
- @cols = []
21
- end
22
-
23
- # Convenience method to directly generate a table. Renders a row for each entry in entries.
24
- # Takes a block that gets the table object as parameter for configuration.
25
- # Returns the generated html for the table.
26
- def self.table(entries, template, options = {})
27
- t = new(entries, template, options)
28
- yield t
29
- t.to_html
30
- end
31
-
32
- # Define a column for the table with the given header, the html_options used for
33
- # each td and a block rendering the contents of a cell for the current entry.
34
- # The columns appear in the order they are defined.
35
- def col(header = '', html_options = {}, &block)
36
- @cols << Col.new(header, html_options, @template, block)
37
- end
38
-
39
- # Convenience method to add one or more attribute columns.
40
- # The attribute name will become the header, the cells will contain
41
- # the formatted attribute value for the current entry.
42
- def attrs(*attrs)
43
- attrs.each do |a|
44
- attr(a)
45
- end
46
- end
47
-
48
- # Define a column for the given attribute and an optional header.
49
- # If no header is given, the attribute name is used. The cell will
50
- # contain the formatted attribute value for the current entry.
51
- def attr(a, header = nil, &block)
52
- header ||= attr_header(a)
53
- block ||= lambda { |e| format_attr(e, a) }
54
- col(header, :class => align_class(a), &block)
55
- end
56
-
57
- # Renders the table as HTML.
58
- def to_html
59
- add_css_class options, 'table'
60
- content_tag :table, options do
61
- content_tag(:thead, html_header) +
62
- content_tag_nested(:tbody, entries) { |e| html_row(e) }
63
- end
64
- end
65
-
66
- # Returns css classes used for alignment of the cell data.
67
- # Based on the column type of the attribute.
68
- def align_class(attr)
69
- entry = entries.first
70
- case column_type(entry, attr)
71
- when :integer, :float, :decimal
72
- 'right' unless association(entry, attr, :belongs_to)
73
- when :boolean
74
- 'center'
75
- end
76
- end
77
-
78
- def attr_header(attr)
79
- captionize(attr, entry_class)
80
- end
81
-
82
- private
83
-
84
- def html_header
85
- content_tag_nested(:tr, cols) { |c| c.html_header }
86
- end
87
-
88
- def html_row(entry)
89
- attrs = {}
90
- attrs[:id] = dom_id(entry) if entry.respond_to?(:dom_id)
91
- content_tag_nested(:tr, cols, attrs) { |c| c.html_cell(entry) }
92
- end
93
-
94
- def entry_class
95
- if entries.respond_to?(:klass)
96
- entries.klass
97
- else
98
- entries.first.class
99
- end
100
- end
101
-
102
- # Helper class to store column information.
103
- class Col < Struct.new(:header, :html_options, :template, :block) #:nodoc:
104
-
105
- delegate :content_tag, :to => :template
106
-
107
- def content(entry)
108
- entry.nil? ? '' : template.capture(entry, &block)
109
- end
110
-
111
- def html_header
112
- content_tag :th, header
113
- end
114
-
115
- def html_cell(entry)
116
- content_tag :td, content(entry), html_options
117
- end
118
-
119
- end
120
-
121
- # Provides headers with sort links. Expects a method :sortable?(attr)
122
- # in the template/controller to tell if an attribute is sortable or not.
123
- # Extracted into an own module for convenience.
124
- module Sorting
125
- # Create a header with sort links and a mark for the current sort direction.
126
- def sort_header(attr, label = nil)
127
- label ||= attr_header(attr)
128
- template.link_to(label, sort_params(attr)) + current_mark(attr)
129
- end
130
-
131
- # Same as :attrs, except that it renders a sort link in the header
132
- # if an attr is sortable.
133
- def sortable_attrs(*attrs)
134
- attrs.each do |a|
135
- template.sortable?(a) ? sortable_attr(a) : attr(a)
136
- end
137
- end
138
-
139
- # Renders a sort link header, otherwise similar to :attr.
140
- def sortable_attr(a, header = nil)
141
- attr(a, sort_header(a, header))
142
- end
143
-
144
- private
145
-
146
- # Request params for the sort link.
147
- def sort_params(attr)
148
- params.merge({:sort => attr, :sort_dir => sort_dir(attr)})
149
- end
150
-
151
- # The sort mark, if any, for the given attribute.
152
- def current_mark(attr)
153
- if current_sort?(attr)
154
- (sort_dir(attr) == 'asc' ? ' &uarr;' : ' &darr;').html_safe
155
- else
156
- ''
157
- end
158
- end
159
-
160
- # Returns true if the given attribute is the current sort column.
161
- def current_sort?(attr)
162
- params[:sort] == attr.to_s
163
- end
164
-
165
- # The sort direction to use in the sort link for the given attribute.
166
- def sort_dir(attr)
167
- current_sort?(attr) && params[:sort_dir] == 'asc' ? 'desc' : 'asc'
168
- end
169
-
170
- # Delegate to template.
171
- def params
172
- template.params
173
- end
174
- end
175
-
176
- include Sorting
177
-
178
- end