dry_crud 1.2.7 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/README.rdoc +60 -27
  2. data/Rakefile +3 -1
  3. data/VERSION +1 -1
  4. data/lib/generators/dry_crud/dry_crud_generator.rb +3 -3
  5. data/lib/generators/dry_crud/templates/INSTALL +3 -1
  6. data/lib/generators/dry_crud/templates/app/controllers/crud_controller.rb +106 -90
  7. data/lib/generators/dry_crud/templates/app/controllers/list_controller.rb +90 -74
  8. data/lib/generators/dry_crud/templates/app/controllers/render_inheritable.rb +34 -33
  9. data/lib/generators/dry_crud/templates/app/helpers/crud_helper.rb +39 -23
  10. data/lib/generators/dry_crud/templates/app/helpers/list_helper.rb +11 -9
  11. data/lib/generators/dry_crud/templates/app/helpers/standard_form_builder.rb +55 -47
  12. data/lib/generators/dry_crud/templates/app/helpers/standard_helper.rb +134 -86
  13. data/lib/generators/dry_crud/templates/app/helpers/standard_table_builder.rb +41 -35
  14. data/lib/generators/dry_crud/templates/app/views/crud/_actions_edit.html.erb +1 -0
  15. data/lib/generators/dry_crud/templates/app/views/crud/edit.html.erb +3 -3
  16. data/lib/generators/dry_crud/templates/app/views/crud/new.html.erb +2 -2
  17. data/lib/generators/dry_crud/templates/app/views/crud/show.html.erb +3 -3
  18. data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.erb +9 -7
  19. data/lib/generators/dry_crud/templates/app/views/list/_search.html.erb +1 -1
  20. data/lib/generators/dry_crud/templates/app/views/list/index.html.erb +4 -4
  21. data/lib/generators/dry_crud/templates/app/views/shared/_error_messages.html.erb +3 -1
  22. data/lib/generators/dry_crud/templates/config/locales/en_crud.yml +63 -0
  23. data/lib/generators/dry_crud/templates/test/crud_test_model.rb +93 -58
  24. data/lib/generators/dry_crud/templates/test/custom_assertions.rb +24 -13
  25. data/lib/generators/dry_crud/templates/test/functional/crud_controller_test_helper.rb +26 -56
  26. data/lib/generators/dry_crud/templates/test/functional/crud_test_models_controller_test.rb +47 -41
  27. data/lib/generators/dry_crud/templates/test/unit/custom_assertions_test.rb +28 -24
  28. data/lib/generators/dry_crud/templates/test/unit/helpers/crud_helper_test.rb +20 -34
  29. data/lib/generators/dry_crud/templates/test/unit/helpers/list_helper_test.rb +39 -53
  30. data/lib/generators/dry_crud/templates/test/unit/helpers/render_inheritable_test.rb +33 -33
  31. data/lib/generators/dry_crud/templates/test/unit/helpers/standard_form_builder_test.rb +27 -27
  32. data/lib/generators/dry_crud/templates/test/unit/helpers/standard_helper_test.rb +103 -50
  33. data/lib/generators/dry_crud/templates/test/unit/helpers/standard_table_builder_test.rb +52 -24
  34. data/test/templates/Gemfile +34 -0
  35. data/test/templates/app/controllers/ajax_controller.rb +3 -3
  36. data/test/templates/app/controllers/application_controller.rb +1 -1
  37. data/test/templates/app/controllers/cities_controller.rb +2 -5
  38. data/test/templates/app/controllers/people_controller.rb +5 -5
  39. data/test/templates/app/controllers/vips_controller.rb +6 -11
  40. data/test/templates/app/helpers/people_helper.rb +2 -2
  41. data/test/templates/app/models/city.rb +9 -9
  42. data/test/templates/app/models/person.rb +5 -4
  43. data/test/templates/app/views/ajax/_actions_index.html.erb +2 -2
  44. data/test/templates/app/views/cities/_form.html.erb +5 -1
  45. data/test/templates/app/views/layouts/_menu.html.erb +3 -3
  46. data/test/templates/app/views/people/_attrs.html.erb +3 -3
  47. data/test/templates/config/database.yml +22 -0
  48. data/test/templates/config/locales/en_cities.yml +56 -0
  49. data/test/templates/config/routes.rb +5 -5
  50. data/test/templates/db/migrate/20100511174904_create_people_and_cities.rb +5 -2
  51. data/test/templates/db/seeds.rb +38 -29
  52. data/test/templates/test/functional/cities_controller_test.rb +12 -12
  53. data/test/templates/test/functional/people_controller_test.rb +10 -10
  54. metadata +11 -7
@@ -1,56 +1,72 @@
1
- # Extension of StandardHelper functionality to provide a set of default
1
+ # Extension of StandardHelper functionality to provide a set of default
2
2
  # attributes for the current model to be used in tables and forms. This helper
3
3
  # is included in CrudController.
4
4
  module CrudHelper
5
5
 
6
- # Renders a generic form for the current entry with :default_attrs or the
7
- # given attribute array, using the StandardFormBuilder.
6
+ # Renders a generic form for the current entry with :default_attrs or the
7
+ # given attribute array, using the StandardFormBuilder. An options hash
8
+ # may be given as the last argument.
8
9
  # If a block is given, a custom form may be rendered and attrs is ignored.
9
- def crud_form(attrs = nil, options = {}, &block)
10
- attrs = default_attrs - [:created_at, :updated_at] unless attrs
11
- standard_form(@entry, attrs, &block)
10
+ def crud_form(*attrs, &block)
11
+ attrs = attrs_or_default(attrs) { default_attrs - [:created_at, :updated_at] }
12
+ standard_form(@entry, *attrs, &block)
12
13
  end
13
-
14
- # Create a table of the @entries variable with the default or
15
- # the passed attributes in its columns.
14
+
15
+ # Create a table of the @entries variable with the default or
16
+ # the passed attributes in its columns. An options hash may be given
17
+ # as the last argument.
16
18
  def crud_table(*attrs, &block)
17
19
  if block_given?
18
20
  list_table(*attrs, &block)
19
- else
20
- attrs = default_attrs if attrs.blank?
21
- list_table(*attrs) do |t|
21
+ else
22
+ attrs = attrs_or_default(attrs) { default_attrs }
23
+ list_table(*attrs) do |t|
22
24
  add_table_actions(t)
23
25
  end
24
26
  end
25
27
  end
26
-
28
+
27
29
  # Adds a set of standard action link column (show, edit, destroy) to the given table.
28
30
  def add_table_actions(table)
29
31
  action_col(table) { |e| link_table_action_show(e) }
30
32
  action_col(table) { |e| link_table_action_edit(e) }
31
33
  action_col(table) { |e| link_table_action_destroy(e) }
32
34
  end
33
-
35
+
36
+ # Action link to show inside a table.
34
37
  def link_table_action_show(record)
35
38
  link_table_action('show', record)
36
39
  end
37
-
40
+
41
+ # Action link to edit inside a table.
38
42
  def link_table_action_edit(record)
39
- link_table_action('edit', edit_polymorphic_path(record))
43
+ link_table_action('edit', edit_polymorphic_path(record))
40
44
  end
41
-
45
+
46
+ # Action link to destroy inside a table.
42
47
  def link_table_action_destroy(record)
43
- link_table_action('delete', record,
44
- :confirm => StandardHelper::CONFIRM_DELETE_MESSAGE,
45
- :method => :delete)
48
+ link_table_action('delete', record,
49
+ :confirm => ti(:confirm_delete),
50
+ :method => :delete)
46
51
  end
47
-
52
+
53
+ # Generic action link inside a table.
48
54
  def link_table_action(image, url, html_options = {})
49
- link_to(action_icon(image), url, html_options)
55
+ link_to(action_icon(image), url, html_options)
50
56
  end
51
-
57
+
58
+ # Defines a column with an action link.
52
59
  def action_col(table, &block)
53
60
  table.col('', :class => 'center', &block)
54
61
  end
55
62
 
63
+ private
64
+
65
+ # Returns default attrs for a crud table if no others are passed.
66
+ def attrs_or_default(attrs)
67
+ options = attrs.extract_options!
68
+ attrs = yield if attrs.blank?
69
+ attrs << options
70
+ end
71
+
56
72
  end
@@ -1,24 +1,26 @@
1
- # Extension of StandardHelper functionality to provide a set of default
1
+ # Extension of StandardHelper functionality to provide a set of default
2
2
  # attributes for the current model to be used in tables and forms. This helper
3
3
  # is included in CrudController.
4
4
  module ListHelper
5
-
6
- # Create a table of the @entries variable with the default or
7
- # the passed attributes in its columns.
5
+
6
+ # Create a table of the @entries variable with the default or
7
+ # the passed attributes in its columns. An options hash may be given
8
+ # as the last argument.
8
9
  def list_table(*attrs, &block)
10
+ options = attrs.extract_options!
9
11
  # only use default attrs if no attrs and no block are given
10
12
  attributes = (block_given? || attrs.present?) ? attrs : default_attrs
11
- table(@entries) do |t|
12
- t.sortable_attrs(*attributes)
13
- yield t if block_given?
13
+ table(@entries, options) do |t|
14
+ t.sortable_attrs(*attributes)
15
+ yield t if block_given?
14
16
  end
15
17
  end
16
-
18
+
17
19
  # The default attributes to use in attrs, list and form partials.
18
20
  # These are all defined attributes except certain special ones like 'id' or 'position'.
19
21
  def default_attrs
20
22
  attrs = model_class.column_names.collect(&:to_sym)
21
23
  attrs - [:id, :position, :password]
22
24
  end
23
-
25
+
24
26
  end
@@ -1,23 +1,22 @@
1
1
  # A form builder that automatically selects the corresponding input field
2
2
  # for ActiveRecord column types. Convenience methods for each column type allow
3
- # one to customize the different fields.
3
+ # one to customize the different fields.
4
4
  # All field methods may be prefixed with 'labeled_' in order to render
5
5
  # a standard label with them.
6
6
  class StandardFormBuilder < ActionView::Helpers::FormBuilder
7
-
8
- BLANK_SELECT_LABEL = 'Please select'
9
- REQUIRED_MARK = '<span class="required">*</span>'.html_safe
10
-
11
- attr_reader :template
12
-
13
- delegate :association, :column_type, :column_property, :captionize,
7
+
8
+ REQUIRED_MARK = '<span class="required">*</span>'.html_safe
9
+
10
+ attr_reader :template
11
+
12
+ delegate :association, :column_type, :column_property, :captionize, :ta,
14
13
  :to => :template
15
-
14
+
16
15
  # Render multiple input fields together with a label for the given attributes.
17
16
  def labeled_input_fields(*attrs)
18
17
  attrs.collect {|a| labeled_input_field(a) }.join("\n").html_safe
19
18
  end
20
-
19
+
21
20
  # Render a standartized label.
22
21
  def label(attr, text = nil, options = {})
23
22
  if attr.is_a?(Symbol) && text.nil? && options.blank?
@@ -26,7 +25,7 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
26
25
  super(attr, text, options)
27
26
  end
28
27
  end
29
-
28
+
30
29
  # Render a corresponding input field for the given attribute.
31
30
  # The input field is chosen based on the ActiveRecord column type.
32
31
  # Use additional html_options for the input element.
@@ -47,58 +46,68 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
47
46
  end
48
47
  end
49
48
  end
50
-
49
+
51
50
  # Render a standard text field.
52
51
  def text_field(attr, html_options = {})
53
52
  super(attr, {:size => 30}.merge(html_options))
54
53
  end
55
-
54
+
56
55
  # Render a standard password field.
57
56
  def password_field(attr, html_options = {})
58
57
  super(attr, {:size => 30}.merge(html_options))
59
58
  end
60
-
59
+
61
60
  # Render a standard text area.
62
61
  def text_area(attr, html_options = {})
63
62
  super(attr, {:rows => 5, :cols => 30}.merge(html_options))
64
63
  end
65
-
64
+
66
65
  # Render a standard string field with column contraints.
67
66
  def string_field(attr, html_options = {})
68
67
  limit = column_property(@object, attr, :limit)
69
68
  html_options = {:maxlength => limit}.merge(html_options) if limit
70
69
  text_field(attr, html_options)
71
70
  end
72
-
71
+
73
72
  # Render a standard number field.
74
73
  def number_field(attr, html_options = {})
75
74
  super(attr, {:size => 15}.merge(html_options))
76
75
  end
77
-
76
+
78
77
  # Render an integer field.
79
78
  def integer_field(attr, html_options = {})
80
79
  number_field(attr, html_options)
81
80
  end
82
-
81
+
83
82
  # Render a float field.
84
83
  def float_field(attr, html_options = {})
85
84
  number_field(attr, html_options)
86
- end
87
-
85
+ end
86
+
88
87
  # Render a decimal field.
89
88
  def decimal_field(attr, html_options = {})
90
89
  number_field(attr, html_options)
91
90
  end
92
-
91
+
93
92
  # Render a boolean field.
94
93
  def boolean_field(attr, html_options = {})
95
94
  check_box(attr, html_options)
96
95
  end
97
-
96
+
98
97
  # Render a field to select a date. You might want to customize this.
99
98
  def date_field(attr, html_options = {})
100
99
  date_select(attr, {}, html_options)
101
100
  end
101
+
102
+ # Render a field to enter a time. You might want to customize this.
103
+ def time_field(attr, html_options = {})
104
+ time_select(attr, {}, html_options)
105
+ end
106
+
107
+ # Render a field to enter a date and time. You might want to customize this.
108
+ def datetime_field(attr, html_options = {})
109
+ datetime_select(attr, {}, html_options)
110
+ end
102
111
 
103
112
  # Render a select element for a :belongs_to association defined by attr.
104
113
  # Use additional html_options for the select element.
@@ -107,38 +116,45 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
107
116
  def belongs_to_field(attr, html_options = {})
108
117
  list = association_entries(attr, html_options)
109
118
  if list.present?
110
- collection_select(attr, list, :id, :label, select_options(attr), html_options)
119
+ collection_select(attr, list, :id, :to_s, select_options(attr), html_options)
111
120
  else
112
- '(none available)'
121
+ ta(:none_available, association(@object, attr))
113
122
  end
114
123
  end
115
-
124
+
116
125
  # Renders a marker if the given attr has to be present.
117
126
  def required_mark(attr)
118
127
  required?(attr) ? REQUIRED_MARK : ''
119
128
  end
120
-
129
+
121
130
  # Render a label for the given attribute with the passed field html section.
122
131
  def labeled(attr, field_html = nil, &block)
123
132
  template.labeled(label(attr), field_html, &block)
124
133
  end
134
+
135
+ # Depending if the given attribute must be present, return
136
+ # only an initial selection prompt or a blank option, respectively.
137
+ def select_options(attr)
138
+ assoc = association(@object, attr)
139
+ required?(attr) ? { :prompt => ta(:please_select, assoc) } :
140
+ { :include_blank => ta(:no_entry, assoc) }
141
+ end
125
142
 
126
- # Dispatch methods starting with 'labeled_' to render a label and the corresponding
143
+ # Dispatch methods starting with 'labeled_' to render a label and the corresponding
127
144
  # input field. E.g. labeled_boolean_field(:checked, {:class => 'bold'})
128
145
  def method_missing(name, *args)
129
146
  if field_method = labeled_field_method?(name)
130
147
  labeled(args.first, send(field_method, *args) + required_mark(args.first))
131
- else
148
+ else
132
149
  super(name, *args)
133
150
  end
134
151
  end
135
-
152
+
136
153
  def respond_to?(name)
137
154
  labeled_field_method?(name).present? || super(name)
138
155
  end
139
-
140
156
  protected
141
-
157
+
142
158
  # Returns true if attr is a non-polymorphic belongs_to association,
143
159
  # for which an input field may be automatically rendered.
144
160
  def belongs_to_association?(attr, type)
@@ -149,41 +165,33 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
149
165
  false
150
166
  end
151
167
  end
152
-
168
+
153
169
  # Returns the list of association entries, either from options[:list],
154
170
  # the instance variable with the pluralized association name or all
155
171
  # entries of the association klass.
156
172
  def association_entries(attr, options)
157
- list = options.delete(:list)
173
+ list = options.delete(:list)
158
174
  unless list
159
175
  assoc = association(@object, attr)
160
176
  list = @template.send(:instance_variable_get, :"@#{assoc.name.to_s.pluralize}")
161
177
  unless list
162
- list = assoc.klass.all(:conditions => assoc.options[:conditions],
163
- :order => assoc.options[:order])
178
+ list = assoc.klass.where(assoc.options[:conditions]).order(assoc.options[:order])
164
179
  end
165
180
  end
166
181
  list
167
182
  end
168
-
183
+
169
184
  # Returns true if the given attribute must be present.
170
185
  def required?(attr)
171
186
  attr = attr.to_s
172
187
  attr, attr_id = attr.end_with?('_id') ? [attr[0..-4], attr] : [attr, "#{attr}_id"]
173
- validators = @object.class.validators_on(attr) +
188
+ validators = @object.class.validators_on(attr) +
174
189
  @object.class.validators_on(attr_id)
175
190
  validators.any? {|v| v.kind == :presence }
176
191
  end
177
-
178
- # Depending if the given attribute must be present, return
179
- # only an initial selection prompt or a blank option, respectively.
180
- def select_options(attr)
181
- required?(attr) ? { :prompt => BLANK_SELECT_LABEL } :
182
- { :include_blank => StandardHelper::NO_ENTRY }
183
- end
184
-
192
+
185
193
  private
186
-
194
+
187
195
  def labeled_field_method?(name)
188
196
  prefix = 'labeled_'
189
197
  if name.to_s.start_with?(prefix)
@@ -191,5 +199,5 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
191
199
  field_method if respond_to?(field_method)
192
200
  end
193
201
  end
194
-
202
+
195
203
  end
@@ -1,36 +1,29 @@
1
- # A view helper to standartize often used functions like formatting,
2
- # tables, forms or action links. This helper is ideally defined in the
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
3
  # ApplicationController.
4
4
  module StandardHelper
5
-
6
- NO_LIST_ENTRIES_MESSAGE = "No entries found"
7
- NO_ENTRY = '(none)'
8
- CONFIRM_DELETE_MESSAGE = 'Do you really want to delete this entry?'
9
-
10
- FLOAT_FORMAT = "%.2f"
11
- TIME_FORMAT = "%H:%M"
5
+
12
6
  EMPTY_STRING = "&nbsp;".html_safe # non-breaking space asserts better css styling.
13
-
7
+
14
8
  ################ FORMATTING HELPERS ##################################
15
9
 
16
10
  # Define an array of associations symbols in your helper that should not get automatically linked.
17
11
  #def no_assoc_links = [:city]
18
-
12
+
19
13
  # Formats a single value
20
14
  def f(value)
21
15
  case value
22
16
  when Fixnum then number_with_delimiter(value)
23
- when Float then FLOAT_FORMAT % value
24
- when Date then value.to_s
25
- when Time then value.strftime(TIME_FORMAT)
26
- when true then 'yes'
27
- when false then 'no'
17
+ when Float then number_with_precision(value, :precision => 2)
18
+ when Date then l(value)
19
+ when Time then l(value, :format => :time)
20
+ when true then t(:"global.yes")
21
+ when false then t(:"global.no")
28
22
  when nil then EMPTY_STRING
29
- else
30
- value.respond_to?(:label) ? value.label : value.to_s
23
+ else value.to_s
31
24
  end
32
25
  end
33
-
26
+
34
27
  # Formats an arbitrary attribute of the given ActiveRecord object.
35
28
  # If no specific format_{attr} method is found, formats the value as follows:
36
29
  # If the value is an associated model, renders the label of this object.
@@ -45,150 +38,190 @@ module StandardHelper
45
38
  format_type(obj, attr)
46
39
  end
47
40
  end
48
-
49
-
41
+
42
+
50
43
  ############## STANDARD HTML SECTIONS ############################
51
-
52
-
44
+
45
+
53
46
  # Renders an arbitrary content with the given label. Used for uniform presentation.
54
47
  def labeled(label, content = nil, &block)
55
48
  content = capture(&block) if block_given?
56
- render(:partial => 'shared/labeled',
57
- :locals => { :label => label, :content => content})
49
+ render 'shared/labeled', :label => label, :content => content
58
50
  end
59
-
51
+
60
52
  # Transform the given text into a form as used by labels or table headers.
61
53
  def captionize(text, clazz = nil)
62
54
  if clazz.respond_to?(:human_attribute_name)
63
55
  clazz.human_attribute_name(text)
64
56
  else
65
- text.to_s.humanize.titleize
57
+ text.to_s.humanize.titleize
66
58
  end
67
59
  end
68
-
69
- # Renders a list of attributes with label and value for a given object.
60
+
61
+ # Renders a list of attributes with label and value for a given object.
70
62
  # Optionally surrounded with a div.
71
63
  def render_attrs(obj, *attrs)
72
- attrs.collect do |a|
64
+ attrs.collect do |a|
73
65
  labeled_attr(obj, a)
74
66
  end.join("\n").html_safe
75
67
  end
76
-
68
+
77
69
  # Renders the formatted content of the given attribute with a label.
78
70
  def labeled_attr(obj, attr)
79
71
  labeled(captionize(attr, obj.class), format_attr(obj, attr))
80
72
  end
81
-
82
- # Renders a table for the given entries. One column is rendered for each attribute passed.
73
+
74
+ # Renders a table for the given entries. One column is rendered for each attribute passed.
83
75
  # If a block is given, the columns defined therein are appended to the attribute columns.
84
76
  # If entries is empty, an appropriate message is rendered.
77
+ # An options hash may be given as the last argument.
85
78
  def table(entries, *attrs, &block)
86
79
  if entries.present?
87
- StandardTableBuilder.table(entries, self) do |t|
80
+ StandardTableBuilder.table(entries, self, attrs.extract_options!) do |t|
88
81
  t.attrs(*attrs)
89
82
  yield t if block_given?
90
83
  end
91
84
  else
92
- content_tag(:div, NO_LIST_ENTRIES_MESSAGE, :class => 'list')
85
+ content_tag(:div, ti(:no_list_entries), :class => 'list')
93
86
  end
94
87
  end
95
-
88
+
96
89
  # Renders a generic form for all given attributes using StandardFormBuilder.
97
90
  # Before the input fields, the error messages are rendered, if present.
98
91
  # The form is rendered with a basic save button.
99
92
  # If a block is given, custom input fields may be rendered and attrs is ignored.
100
- def standard_form(object, attrs = [], options = {}, &block)
101
- form_for(object, {:builder => StandardFormBuilder}.merge(options)) do |form|
102
- content = render(:partial => 'shared/error_messages',
103
- :locals => {:errors => object.errors})
104
-
105
- content << if block_given?
106
- capture(form, &block)
93
+ # An options hash may be given as the last argument.
94
+ def standard_form(object, *attrs, &block)
95
+ form_for(object, {:builder => StandardFormBuilder}.merge(attrs.extract_options!)) do |form|
96
+ content = render('shared/error_messages', :errors => object.errors, :object => object)
97
+
98
+ content << if block_given?
99
+ capture(form, &block)
107
100
  else
108
101
  form.labeled_input_fields(*attrs)
109
102
  end
110
-
111
- content << labeled(nil, form.submit("Save") + cancel_link(object))
103
+
104
+ content << labeled(nil, form.submit(ti(:"button.save")) + cancel_link(object))
112
105
  content.html_safe
113
106
  end
114
107
  end
115
-
108
+
116
109
  def cancel_link(object)
117
- link_to("Cancel", polymorphic_path(object), :class => 'cancel')
110
+ link_to(ti(:"button.cancel"), polymorphic_path(object), :class => 'cancel')
118
111
  end
119
-
112
+
120
113
  # Alternate table row
121
114
  def tr_alt(cycle_name = 'row_class', &block)
122
115
  content_tag(:tr, :class => cycle("even", "odd", :name => cycle_name), &block)
123
116
  end
124
117
 
118
+ # Renders a div with clear:both style.
125
119
  def clear
126
120
  content_tag(:div, '', :class => 'clear')
127
121
  end
128
-
129
-
122
+
123
+
130
124
  ######## ACTION LINKS ###################################################### :nodoc:
131
-
125
+
132
126
  # Standard link action to the show page of a given record.
133
127
  def link_action_show(record)
134
- link_action 'Show', 'show', record
128
+ link_action ti(:"link.show"), 'show', record
135
129
  end
136
-
130
+
137
131
  # Standard link action to the edit page of a given record.
138
132
  def link_action_edit(record)
139
- link_action 'Edit', 'edit', edit_polymorphic_path(record)
133
+ link_action ti(:"link.edit"), 'edit', edit_polymorphic_path(record)
140
134
  end
141
-
135
+
142
136
  # Standard link action to the destroy action of a given record.
143
137
  def link_action_destroy(record)
144
- link_action 'Delete', 'delete', record,
145
- :confirm => CONFIRM_DELETE_MESSAGE,
138
+ link_action ti(:"link.delete"), 'delete', record,
139
+ :confirm => ti(:confirm_delete),
146
140
  :method => :delete
147
141
  end
148
-
142
+
149
143
  # Standard link action to the list page.
150
144
  def link_action_index(url_options = {:action => 'index', :returning => true})
151
- link_action 'List', 'list', url_options
145
+ link_action ti(:"link.list"), 'list', url_options
152
146
  end
153
-
147
+
154
148
  # Standard link action to the new page.
155
149
  def link_action_add(url_options = {:action => 'new'})
156
- link_action 'Add', 'add', url_options
150
+ link_action ti(:"link.add"), 'add', url_options
157
151
  end
158
-
152
+
159
153
  # A generic helper method to create action links.
160
154
  # These link could be styled to look like buttons, for example.
161
155
  def link_action(label, icon = nil, url = {}, html_options = {})
162
- link_to(icon ? action_icon(icon, label) : label,
163
- url,
156
+ link_to(icon ? action_icon(icon, label) : label,
157
+ url,
164
158
  {:class => 'action'}.merge(html_options))
165
159
  end
166
-
160
+
161
+ # Outputs an icon for an action with an optional label.
167
162
  def action_icon(icon, label = nil)
168
- html = image_tag("actions/#{icon}.png", :size => '16x16')
163
+ html = image_tag("actions/#{icon}.png", :size => '16x16')
169
164
  html << ' ' << label if label
170
165
  html
171
166
  end
172
-
173
- protected
174
-
175
- # Helper methods that are not directly called from templates.
176
-
177
- # Formats an active record association
178
- def format_assoc(obj, assoc)
179
- if assoc_val = obj.send(assoc.name)
180
- link_to_unless(no_assoc_link?(assoc, assoc_val), assoc_val.label, assoc_val)
167
+
168
+ # Translates the passed key by looking it up over the template lookup path
169
+ # (i.e., usually the controller hierarchy). The key is searched in the following
170
+ # order:
171
+ # - {controller}.{current_partial}.{key}
172
+ # - {controller}.{current_action}.{key}
173
+ # - {controller}.global.{key}
174
+ # - {parent_controller}.{current_partial}.{key}
175
+ # - {parent_controller}.{current_action}.{key}
176
+ # - {parent_controller}.global.{key}
177
+ # - ...
178
+ # - global.{key}
179
+ def translate_inheritable(key, variables = {})
180
+ defaults = []
181
+ if controller.class.respond_to?(:template_lookup_path)
182
+ partial = @_virtual_path ? @_virtual_path.gsub(%r{.*/_?}, "") : nil
183
+ controller.class.template_lookup_path.each do |folder|
184
+ defaults << :"#{folder}.#{partial}.#{key}" if partial
185
+ defaults << :"#{folder}.#{action_name}.#{key}"
186
+ defaults << :"#{folder}.global.#{key}"
187
+ end
181
188
  else
182
- NO_ENTRY
189
+ defaults << :"#{controller_name}.#{action_name}.#{key}"
190
+ defaults << :"#{controller_name}.global.#{key}"
183
191
  end
192
+ defaults << :"global.#{key}"
193
+
194
+ variables[:default] ||= defaults
195
+ t(defaults.shift, variables)
184
196
  end
185
197
 
186
- # Returns true if no link should be created when formatting the given association.
187
- def no_assoc_link?(assoc, val)
188
- (respond_to?(:no_assoc_links) && no_assoc_links.to_a.include?(assoc.name.to_sym)) ||
189
- !respond_to?("#{val.class.name.underscore}_path".to_sym)
198
+ alias_method :ti, :translate_inheritable
199
+
200
+ # Translates the passed key for an active record association. This helper is used
201
+ # for rendering association dependent keys in forms like :no_entry, :none_available or
202
+ # :please_select.
203
+ # The key is looked up in the following order:
204
+ # - activerecord.associations.models.{model_name}.{association_name}.{key}
205
+ # - activerecord.associations.{association_model_name}.{key}
206
+ # - global.associations.{key}
207
+ def translate_association(key, assoc = nil, variables = {})
208
+ primary = if assoc
209
+ variables[:default] ||= [:"activerecord.associations.#{assoc.klass.name.underscore}.#{key}",
210
+ :"global.associations.#{key}"]
211
+ :"activerecord.associations.models.#{assoc.active_record.name.underscore}.#{assoc.name}.#{key}"
212
+ else
213
+ :"global.associations.#{key}"
214
+ end
215
+ t(primary, variables)
190
216
  end
191
217
 
218
+ alias_method :ta, :translate_association
219
+
220
+
221
+ protected
222
+
223
+ # Helper methods that are not directly called from templates.
224
+
192
225
  # Formats an arbitrary attribute of the given object depending on its data type.
193
226
  # For ActiveRecords, take the defined data type into account for special types
194
227
  # that have no own object class.
@@ -204,24 +237,39 @@ module StandardHelper
204
237
  else f(val)
205
238
  end
206
239
  end
207
-
240
+
208
241
  # Returns the ActiveRecord column type or nil.
209
242
  def column_type(obj, attr)
210
243
  column_property(obj, attr, :type)
211
244
  end
212
-
245
+
213
246
  # Returns an ActiveRecord column property for the passed attr or nil
214
247
  def column_property(obj, attr, property)
215
248
  if obj.respond_to?(:column_for_attribute)
216
249
  column = obj.column_for_attribute(attr)
217
250
  column.try(property)
218
- end
251
+ end
219
252
  end
220
-
253
+
254
+ # Formats an active record association
255
+ def format_assoc(obj, assoc)
256
+ if assoc_val = obj.send(assoc.name)
257
+ link_to_unless(no_assoc_link?(assoc, assoc_val), assoc_val, assoc_val)
258
+ else
259
+ ta(:no_entry, assoc)
260
+ end
261
+ end
262
+
263
+ # Returns true if no link should be created when formatting the given association.
264
+ def no_assoc_link?(assoc, val)
265
+ (respond_to?(:no_assoc_links) && no_assoc_links.to_a.include?(assoc.name.to_sym)) ||
266
+ !respond_to?("#{val.class.name.underscore}_path".to_sym)
267
+ end
268
+
221
269
  # Returns the association proxy for the given attribute. The attr parameter
222
270
  # may be the _id column or the association name. If a macro (e.g. :belongs_to)
223
271
  # is given, the association must be of this type, otherwise, any association
224
- # is returned. Returns nil if no association (or not of the given macro) was
272
+ # is returned. Returns nil if no association (or not of the given macro) was
225
273
  # found.
226
274
  def association(obj, attr, macro = nil)
227
275
  if obj.class.respond_to?(:reflect_on_association)
@@ -230,5 +278,5 @@ module StandardHelper
230
278
  assoc if assoc && (macro.nil? || assoc.macro == macro)
231
279
  end
232
280
  end
233
-
281
+
234
282
  end