view_mapper 0.3.3 → 0.3.4

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.
Files changed (81) hide show
  1. data/README.rdoc +3 -1
  2. data/VERSION +1 -1
  3. data/lib/view_mapper.rb +1 -0
  4. data/lib/view_mapper/belongs_to_parent_models.rb +12 -26
  5. data/lib/view_mapper/has_many_child_models.rb +9 -9
  6. data/lib/view_mapper/model_info.rb +56 -18
  7. data/lib/view_mapper/views/belongs_to/belongs_to_view.rb +14 -0
  8. data/lib/view_mapper/views/belongs_to_auto_complete/belongs_to_auto_complete_view.rb +9 -2
  9. data/lib/view_mapper/views/has_many/templates/helper.rb +1 -1
  10. data/lib/view_mapper/views/has_many/templates/view_child_form.html.erb +1 -1
  11. data/lib/view_mapper/views/has_many/templates/view_form.html.erb +1 -1
  12. data/lib/view_mapper/views/has_many_existing/has_many_existing_view.rb +126 -0
  13. data/lib/view_mapper/views/has_many_existing/templates/model.rb +21 -0
  14. data/lib/view_mapper/views/has_many_existing/templates/view_child_form.html.erb +16 -0
  15. data/lib/view_mapper/views/has_many_existing/templates/view_form.html.erb +20 -0
  16. data/lib/view_mapper/views/has_many_existing/templates/view_show.html.erb +26 -0
  17. data/test/generators/scaffold_for_view/scaffold_for_view_generator_test.rb +15 -15
  18. data/test/generators/view_for/view_for_generator_test.rb +18 -18
  19. data/test/model_info_test.rb +91 -20
  20. data/test/test_helper.rb +75 -105
  21. data/test/views/auto_complete/auto_complete_test.rb +104 -102
  22. data/test/views/auto_complete/expected_templates/edit.html.erb +6 -6
  23. data/test/views/auto_complete/expected_templates/expected_routes.rb +1 -1
  24. data/test/views/auto_complete/expected_templates/index.html.erb +10 -10
  25. data/test/views/auto_complete/expected_templates/new.html.erb +5 -5
  26. data/test/views/auto_complete/expected_templates/show.html.erb +6 -6
  27. data/test/views/auto_complete/expected_templates/{testies.html.erb → test_models.html.erb} +1 -1
  28. data/test/views/auto_complete/expected_templates/test_models_controller.rb +89 -0
  29. data/test/views/belongs_to/belongs_to_test.rb +238 -202
  30. data/test/views/belongs_to/expected_templates/_form.html.erb +4 -4
  31. data/test/views/belongs_to/expected_templates/child_model.rb +10 -0
  32. data/test/views/belongs_to/expected_templates/create_child_models.rb +18 -0
  33. data/test/views/belongs_to/expected_templates/edit.html.erb +4 -4
  34. data/test/views/belongs_to/expected_templates/index.html.erb +11 -11
  35. data/test/views/belongs_to/expected_templates/new.html.erb +3 -3
  36. data/test/views/belongs_to/expected_templates/show.html.erb +7 -7
  37. data/test/views/belongs_to_auto_complete/belongs_to_auto_complete_test.rb +440 -406
  38. data/test/views/belongs_to_auto_complete/expected_templates/_form.html.erb +4 -4
  39. data/test/views/belongs_to_auto_complete/expected_templates/child_model.rb +16 -0
  40. data/test/views/belongs_to_auto_complete/expected_templates/{some_other_models.html.erb → child_models.html.erb} +1 -1
  41. data/test/views/belongs_to_auto_complete/expected_templates/child_models_controller.rb +89 -0
  42. data/test/views/belongs_to_auto_complete/expected_templates/create_child_models.rb +18 -0
  43. data/test/views/belongs_to_auto_complete/expected_templates/edit.html.erb +4 -4
  44. data/test/views/belongs_to_auto_complete/expected_templates/expected_routes.rb +2 -2
  45. data/test/views/belongs_to_auto_complete/expected_templates/index.html.erb +11 -11
  46. data/test/views/belongs_to_auto_complete/expected_templates/new.html.erb +3 -3
  47. data/test/views/belongs_to_auto_complete/expected_templates/show.html.erb +7 -7
  48. data/test/views/has_many/expected_templates/_form.html.erb +8 -8
  49. data/test/views/has_many/expected_templates/{_person.html.erb → _second_child_model.html.erb} +5 -5
  50. data/test/views/has_many/expected_templates/create_parent_models.rb +16 -0
  51. data/test/views/has_many/expected_templates/edit.html.erb +4 -4
  52. data/test/views/has_many/expected_templates/index.html.erb +7 -7
  53. data/test/views/has_many/expected_templates/new.html.erb +3 -3
  54. data/test/views/has_many/expected_templates/{parent.rb → parent_model.rb} +5 -5
  55. data/test/views/has_many/expected_templates/show.html.erb +15 -15
  56. data/test/views/has_many/has_many_view_test.rb +334 -292
  57. data/test/views/has_many_existing/expected_templates/_assignment.html.erb +14 -0
  58. data/test/views/has_many_existing/expected_templates/_form.html.erb +16 -0
  59. data/test/views/{has_many/expected_templates/create_parents.rb → has_many_existing/expected_templates/create_programmers.rb} +3 -3
  60. data/test/views/has_many_existing/expected_templates/edit.html.erb +11 -0
  61. data/test/views/has_many_existing/expected_templates/index.html.erb +20 -0
  62. data/test/views/has_many_existing/expected_templates/new.html.erb +10 -0
  63. data/test/views/has_many_existing/expected_templates/programmer.rb +10 -0
  64. data/test/views/has_many_existing/expected_templates/show.html.erb +20 -0
  65. data/test/views/has_many_existing/has_many_existing_test.rb +495 -0
  66. data/test/views/paperclip/expected_templates/{create_testies.rb → create_test_models.rb} +3 -3
  67. data/test/views/paperclip/expected_templates/edit.html.erb +4 -4
  68. data/test/views/paperclip/expected_templates/index.html.erb +10 -10
  69. data/test/views/paperclip/expected_templates/new.html.erb +3 -3
  70. data/test/views/paperclip/expected_templates/show.html.erb +8 -8
  71. data/test/views/paperclip/expected_templates/{testy.rb → test_model.rb} +1 -1
  72. data/test/views/paperclip/paperclip_view_test.rb +254 -226
  73. data/view_mapper.gemspec +43 -27
  74. metadata +64 -37
  75. data/test/views/auto_complete/expected_templates/actual_index +0 -26
  76. data/test/views/auto_complete/expected_templates/testies_controller.rb +0 -89
  77. data/test/views/belongs_to/expected_templates/create_some_other_models.rb +0 -18
  78. data/test/views/belongs_to/expected_templates/some_other_model.rb +0 -10
  79. data/test/views/belongs_to_auto_complete/expected_templates/create_some_other_models.rb +0 -18
  80. data/test/views/belongs_to_auto_complete/expected_templates/some_other_model.rb +0 -16
  81. data/test/views/belongs_to_auto_complete/expected_templates/some_other_models_controller.rb +0 -89
@@ -45,7 +45,9 @@ This is the same as view_for, but will also generate a new model at the same tim
45
45
 
46
46
  {belongs_to}[http://patshaughnessy.net/2010/1/25/creating-associations-to-existing-data-part-1-belongs_to-scaffolding]: Generates scaffolding that allows you to select an existing, associated model.
47
47
 
48
- belongs_to_auto_complete: Generates scaffolding that allows you to select an existing, associated model using auto_complete.
48
+ {belongs_to_auto_complete}[http://patshaughnessy.net/2010/2/13/creating-associations-to-existing-data-part-2-belongs_to-with-auto_complete]: Generates scaffolding that allows you to select an existing, associated model using auto_complete.
49
+
50
+ {has_many_existing}[http://patshaughnessy.net/2010/4/4/creating-associations-to-existing-data-part-3-has_many-through-scaffolding]: Generates scaffolding for a complex form to edit two models that have a has_many, :through association with a third model. Use this if you have a many-many relationship with existing data.
49
51
 
50
52
  == Examples
51
53
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.3
1
+ 0.3.4
@@ -9,3 +9,4 @@ require 'view_mapper/views/paperclip/paperclip_view'
9
9
  require 'view_mapper/views/has_many/has_many_view'
10
10
  require 'view_mapper/views/belongs_to/belongs_to_view'
11
11
  require 'view_mapper/views/belongs_to_auto_complete/belongs_to_auto_complete_view'
12
+ require 'view_mapper/views/has_many_existing/has_many_existing_view'
@@ -1,20 +1,6 @@
1
1
  module ViewMapper
2
2
  module BelongsToParentModels
3
3
 
4
- def manifest
5
- m = super.edit do |action|
6
- action unless is_model_dependency_action(action) || !valid
7
- end
8
- if valid
9
- m.template(
10
- "view_form.html.erb",
11
- File.join('app/views', controller_class_path, controller_file_name, "_form.html.erb")
12
- )
13
- add_model_actions(m) unless view_only?
14
- end
15
- m
16
- end
17
-
18
4
  def add_model_actions(m)
19
5
  m.directory(File.join('test/fixtures', class_path))
20
6
  m.template 'model.erb', File.join('app/models', class_path, "#{file_name}.rb")
@@ -70,30 +56,30 @@ module ViewMapper
70
56
  end
71
57
  return false
72
58
  end
73
- parents.reject! { |parent_model| !validate_parent_model(parent_model) }
59
+ parents.reject! { |parent_model| !validate_parent_model(parent_model, class_name, view_only? ? model : nil) }
74
60
  @parent_models = parents
75
61
  !parents.empty?
76
62
  end
77
63
 
78
- def validate_parent_model(parent_model)
64
+ def validate_parent_model(parent_model, child_model_name, child_model, check_setter_method = false)
79
65
  parent_model_name = parent_model.name
80
66
  if !parent_model.valid?
81
67
  logger.error parent_model.error
82
68
  return false
83
- elsif view_only? && !model.belongs_to?(parent_model_name)
84
- logger.warning "Model #{model.name} does not belong to model #{parent_model_name}."
69
+ elsif child_model && !child_model.belongs_to?(parent_model_name)
70
+ logger.warning "Model #{child_model.name} does not belong to model #{parent_model_name}."
85
71
  return false
86
- elsif view_only? && !model.has_method?(virtual_attribute_for(parent_model))
87
- logger.warning "Model #{model.name} does not have a method #{virtual_attribute_for(parent_model)}."
72
+ elsif child_model && !child_model.has_method?(virtual_attribute_for(parent_model))
73
+ logger.warning "Model #{child_model.name} does not have a method #{virtual_attribute_for(parent_model)}."
88
74
  return false
89
- elsif view_only? && !model.has_method?(virtual_attribute_setter_for(parent_model))
90
- logger.warning "Model #{model.name} does not have a method #{virtual_attribute_setter_for(parent_model)}."
75
+ elsif child_model && check_setter_method && !child_model.has_method?(virtual_attribute_setter_for(parent_model))
76
+ logger.warning "Model #{child_model.name} does not have a method #{virtual_attribute_setter_for(parent_model)}."
91
77
  return false
92
- elsif view_only? && !model.has_foreign_key_for?(parent_model_name)
93
- logger.warning "Model #{class_name} does not contain a foreign key for #{parent_model_name}."
78
+ elsif child_model && !child_model.has_foreign_key_for?(parent_model_name)
79
+ logger.warning "Model #{child_model.name} does not contain a foreign key for #{parent_model_name}."
94
80
  return false
95
- elsif !parent_model.has_many?(class_name.pluralize)
96
- logger.warning "Model #{parent_model_name} does not contain a has_many association for #{class_name}."
81
+ elsif !parent_model.has_many?(child_model_name.pluralize)
82
+ logger.warning "Model #{parent_model_name} does not contain a has_many association for #{child_model_name}."
97
83
  return false
98
84
  elsif !parent_model.has_method?(field_for(parent_model)) && !parent_model.has_column?(field_for(parent_model))
99
85
  logger.warning "Model #{parent_model_name} does not have a #{field_for(parent_model)} attribute."
@@ -82,26 +82,26 @@ module ViewMapper
82
82
  end
83
83
  return false
84
84
  end
85
- cms.reject! { |child_model| !validate_child_model(child_model) }
85
+ cms.reject! { |child_model| !validate_child_model(child_model, class_name, view_only? ? model : nil) }
86
86
  @child_models = cms
87
87
  !cms.empty?
88
88
  end
89
89
 
90
- def validate_child_model(child_model)
90
+ def validate_child_model(child_model, parent_model_name, parent_model)
91
91
  if !child_model.valid?
92
92
  logger.error child_model.error
93
93
  return false
94
- elsif view_only? && !model.accepts_nested_attributes_for?(child_model)
95
- logger.warning "Model #{model.name} does not accept nested attributes for model #{child_model.name}."
94
+ elsif parent_model && !parent_model.accepts_nested_attributes_for?(child_model)
95
+ logger.warning "Model #{parent_model.name} does not accept nested attributes for model #{child_model.name}."
96
96
  return false
97
97
  else
98
- if child_model.has_many?(class_name.pluralize) || child_model.has_and_belongs_to_many?(class_name.pluralize)
98
+ if child_model.has_many?(parent_model_name.pluralize) || child_model.has_and_belongs_to_many?(parent_model_name.pluralize)
99
99
  true
100
- elsif !child_model.belongs_to?(class_name)
101
- logger.warning "Model #{child_model.name} does not contain a belongs_to association for #{class_name}."
100
+ elsif !child_model.belongs_to?(parent_model_name)
101
+ logger.warning "Model #{child_model.name} does not contain a belongs_to association for #{parent_model_name}."
102
102
  return false
103
- elsif !child_model.has_foreign_key_for?(class_name)
104
- logger.warning "Model #{child_model.name} does not contain a foreign key for #{class_name}."
103
+ elsif !child_model.has_foreign_key_for?(parent_model_name)
104
+ logger.warning "Model #{child_model.name} does not contain a foreign key for #{parent_model_name}."
105
105
  return false
106
106
  end
107
107
  end
@@ -1,10 +1,10 @@
1
1
  module ViewMapper
2
2
  class ModelInfo
3
3
 
4
- attr_reader :model
5
- attr_reader :name
6
- attr_reader :attributes
7
- attr_reader :error
4
+ attr_reader :model
5
+ attr_accessor :through_model # has_many :through => XYZ
6
+ attr_reader :name
7
+ attr_reader :error
8
8
 
9
9
  def initialize(model_name)
10
10
  @model = find_model(model_name)
@@ -52,18 +52,47 @@ module ViewMapper
52
52
  end
53
53
 
54
54
  def child_models
55
- model_info_array_for_association(:has_many)
55
+ @child_models ||= model_info_array_for_association(:has_many)
56
56
  end
57
57
 
58
58
  def parent_models
59
- model_info_array_for_association(:belongs_to)
59
+ @parent_models ||= model_info_array_for_association(:belongs_to)
60
60
  end
61
61
 
62
- def model_info_array_for_association(association_type)
63
- model.reflections.select { |key, value| value.macro == association_type }.collect do |kvpair|
64
- kvpair[0].to_s.singularize
65
- end.sort.collect do |model_name|
66
- ModelInfo.new model_name
62
+ def has_many_through_models
63
+ @has_many_through_models ||= model_info_array_for_association(:has_many, ActiveRecord::Reflection::ThroughReflection)
64
+ end
65
+
66
+ def find_through_model(source_model_name)
67
+ reflections_for_association(:has_many, ActiveRecord::Reflection::ThroughReflection).each do |kvpair|
68
+ reflection_model_name = kvpair[0].to_s.singularize
69
+ if reflection_model_name == source_model_name.underscore
70
+ reflection = kvpair[1]
71
+ return ModelInfo.new(reflection.options[:through].to_s.singularize)
72
+ end
73
+ end
74
+ nil
75
+ end
76
+
77
+ def reflections_for_association(association_type, type)
78
+ model.reflections.select { |key, value| value.macro == association_type && value.is_a?(type) }
79
+ end
80
+
81
+ def model_info_from_reflection(reflection_model_name, reflection)
82
+ model_info = ModelInfo.new(reflection_model_name)
83
+ if reflection.is_a? ActiveRecord::Reflection::ThroughReflection
84
+ model_info.through_model = ModelInfo.new reflection.options[:through].to_s.singularize
85
+ end
86
+ model_info
87
+ end
88
+
89
+ def model_info_array_for_association(association_type, type = ActiveRecord::Reflection::AssociationReflection)
90
+ reflections_for_association(association_type, type).collect do |kvpair|
91
+ reflection_model_name = kvpair[0].to_s.singularize
92
+ reflection = kvpair[1]
93
+ model_info_from_reflection(reflection_model_name, reflection)
94
+ end.sort do |a, b|
95
+ a.name <=> b.name
67
96
  end
68
97
  end
69
98
 
@@ -77,18 +106,27 @@ module ViewMapper
77
106
  end
78
107
 
79
108
  def belongs_to?(parent_model_name)
80
- has_association_for? :belongs_to, parent_model_name
109
+ !association_for(:belongs_to, parent_model_name).nil?
81
110
  end
82
111
 
83
112
  def has_many?(child_model_name)
84
- has_association_for? :has_many, child_model_name
113
+ !association_for(:has_many, child_model_name).nil?
85
114
  end
86
115
 
87
116
  def has_and_belongs_to_many?(model_name)
88
- has_association_for? :has_and_belongs_to_many, model_name
117
+ !association_for(:has_and_belongs_to_many, model_name).nil?
118
+ end
119
+
120
+ def has_many_through?(model_name)
121
+ reflection = association_for(:has_many, model_name.pluralize)
122
+ reflection && reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
89
123
  end
90
124
 
91
125
  def has_foreign_key_for?(parent_model_name)
126
+ !foreign_key_for(parent_model_name).nil?
127
+ end
128
+
129
+ def foreign_key_for(parent_model_name)
92
130
  model.columns.detect { |col| is_foreign_key_for?(col, parent_model_name) }
93
131
  end
94
132
 
@@ -140,10 +178,10 @@ module ViewMapper
140
178
  end
141
179
  end
142
180
 
143
- def has_association_for?(association, model_name)
144
- !model.reflections.values.detect do |reflection|
181
+ def association_for(association, model_name)
182
+ model.reflections.values.detect do |reflection|
145
183
  reflection.name == model_name.underscore.to_sym && reflection.macro == association
146
- end.nil?
184
+ end
147
185
  end
148
186
 
149
187
  def is_paperclip_column?(col)
@@ -161,7 +199,7 @@ module ViewMapper
161
199
  def has_column_for_attachment(attachment, paperclip_col)
162
200
  has_column = model.columns.map {|col| col.name}.include?(paperclip_col)
163
201
  if !has_column
164
- @error = "Column \'#{paperclip_col}\' does not exist. First run script/generate paperclip #{name.downcase} #{attachment}."
202
+ @error = "Column \'#{paperclip_col}\' does not exist. First run script/generate paperclip #{name.underscore} #{attachment}."
165
203
  end
166
204
  has_column
167
205
  end
@@ -11,6 +11,20 @@ module ViewMapper
11
11
  [ BelongsToView.source_root, File.expand_path(source_root), File.join(self.class.lookup('model').path, 'templates') ]
12
12
  end
13
13
 
14
+ def manifest
15
+ m = super.edit do |action|
16
+ action unless is_model_dependency_action(action) || !valid
17
+ end
18
+ if valid
19
+ m.template(
20
+ "view_form.html.erb",
21
+ File.join('app/views', controller_class_path, controller_file_name, "_form.html.erb")
22
+ )
23
+ add_model_actions(m) unless view_only?
24
+ end
25
+ m
26
+ end
27
+
14
28
  def validate
15
29
  super
16
30
  @valid &&= validate_parent_models
@@ -12,8 +12,15 @@ module ViewMapper
12
12
  end
13
13
 
14
14
  def manifest
15
- m = super
15
+ m = super.edit do |action|
16
+ action unless is_model_dependency_action(action) || !valid
17
+ end
16
18
  if valid
19
+ m.template(
20
+ "view_form.html.erb",
21
+ File.join('app/views', controller_class_path, controller_file_name, "_form.html.erb")
22
+ )
23
+ add_model_actions(m) unless view_only?
17
24
  parent_models.reverse.each do |parent_model|
18
25
  m.route :name => 'connect',
19
26
  :path => auto_complete_for_method(parent_model),
@@ -34,7 +41,7 @@ module ViewMapper
34
41
  @valid &&= validate_parent_models
35
42
  end
36
43
 
37
- def validate_parent_model(parent_model)
44
+ def validate_parent_model(parent_model, child_model_name, child_model, check_setter_method = true)
38
45
  valid = super
39
46
  if valid && !parent_model.has_column?(field_for(parent_model))
40
47
  logger.warning "Model #{parent_model.name} does not have a #{field_for(parent_model)} column."
@@ -1,7 +1,7 @@
1
1
  module <%= controller_class_name %>Helper
2
2
 
3
3
  def remove_child_link(name, form_builder)
4
- form_builder.hidden_field(:_delete) + link_to_function(name, "remove_child(this)")
4
+ form_builder.hidden_field(:_destroy) + link_to_function(name, "remove_child(this)")
5
5
  end
6
6
 
7
7
  def add_child_link(name, child, form_builder)
@@ -6,7 +6,7 @@
6
6
  </p>
7
7
  <% end -%>
8
8
  <p>
9
- <%%= f.hidden_field :_delete, :class => 'delete' %>
9
+ <%%= f.hidden_field :_destroy, :class => 'delete' %>
10
10
  <%%= remove_child_link 'remove', f %>
11
11
  </p>
12
12
  </div>
@@ -15,6 +15,6 @@
15
15
  </div>
16
16
 
17
17
  <p>
18
- <%%= add_child_link 'Add a <%= child_model.name %>', '<%= child_model.name.underscore %>', f %>
18
+ <%%= add_child_link 'Add <%= child_model.name %>', '<%= child_model.name.underscore %>', f %>
19
19
  </p>
20
20
  <% end -%>
@@ -0,0 +1,126 @@
1
+ module ViewMapper
2
+ module HasManyExistingView
3
+
4
+ include BelongsToParentModels
5
+ include HasManyChildModels
6
+
7
+ def self.source_root
8
+ File.expand_path(File.dirname(__FILE__) + "/templates")
9
+ end
10
+
11
+ def source_roots_for_view
12
+ [
13
+ HasManyExistingView.source_root,
14
+ HasManyView.source_root,
15
+ File.expand_path(source_root),
16
+ File.join(self.class.lookup('model').path, 'templates')
17
+ ]
18
+ end
19
+
20
+ def manifest
21
+ m = super.edit do |action|
22
+ action unless is_child_model_action?(action)
23
+ end
24
+ add_through_models_manifest(m)
25
+ m
26
+ end
27
+
28
+ def add_through_models_manifest(m)
29
+ add_child_model_actions(m) if valid && !view_only?
30
+ add_through_model_forms(m) if valid
31
+ m
32
+ end
33
+
34
+ def add_through_model_forms(m)
35
+ m.template(
36
+ "view_show.html.erb",
37
+ File.join('app/views', controller_class_path, controller_file_name, "show.html.erb"),
38
+ { :assigns => { :has_many_through_models => has_many_through_models } }
39
+ )
40
+ m.template(
41
+ "view_form.html.erb",
42
+ File.join('app/views', controller_class_path, controller_file_name, "_form.html.erb")
43
+ )
44
+ has_many_through_models.each do |hmt_model|
45
+ m.template(
46
+ "view_child_form.html.erb",
47
+ File.join('app/views', controller_class_path, controller_file_name, "_#{hmt_model.through_model.name.underscore}.html.erb"),
48
+ { :assigns => { :hmt_model => hmt_model } }
49
+
50
+ )
51
+ end
52
+ m.file('nested_attributes.js', 'public/javascripts/nested_attributes.js')
53
+ m
54
+ end
55
+
56
+ def validate
57
+ super
58
+ @valid &&= validate_hmt_models
59
+ end
60
+
61
+ def has_many_through_models
62
+ @hmt_models ||= find_hmt_models
63
+ end
64
+
65
+ def find_hmt_models
66
+ if view_param
67
+ view_param.split(',').collect do |param|
68
+ hmt_model_info_from_param(param)
69
+ end
70
+ elsif view_only?
71
+ model.has_many_through_models
72
+ else
73
+ []
74
+ end
75
+ end
76
+
77
+ def hmt_model_info_from_param(param)
78
+ if /(.*)\[(.*)\]/.match(param)
79
+ hmt_model = ModelInfo.new($1.singularize)
80
+ select_parent_by hmt_model, $2
81
+ else
82
+ hmt_model = ModelInfo.new(param.singularize)
83
+ end
84
+ hmt_model
85
+ end
86
+
87
+ def validate_hmt_models
88
+ models = has_many_through_models
89
+ if models.empty?
90
+ if view_only?
91
+ logger.error "No has_many through associations exist in class #{model.name}."
92
+ else
93
+ logger.error "No has_many through association specified."
94
+ end
95
+ return false
96
+ end
97
+ models.reject! { |hmt_model| !validate_hmt_model(hmt_model) }
98
+ @hmt_models = models
99
+ !models.empty?
100
+ end
101
+
102
+ def validate_hmt_model(hmt_model)
103
+ if !hmt_model.valid?
104
+ logger.error hmt_model.error
105
+ return false
106
+ elsif !hmt_model.has_many_through?(class_name)
107
+ logger.warning "Model #{hmt_model.name} does not contain a has_many through association for #{class_name}."
108
+ return false
109
+ end
110
+
111
+ hmt_model.through_model = hmt_model.find_through_model(class_name) if hmt_model.through_model.nil?
112
+ if !hmt_model.through_model.valid?
113
+ logger.error hmt_model.through_model.error
114
+ return false
115
+ elsif !validate_parent_model(hmt_model, hmt_model.through_model.name, hmt_model.through_model)
116
+ return false
117
+ elsif !validate_child_model(hmt_model.through_model, class_name, view_only? ? model : nil)
118
+ return false
119
+ elsif !validate_child_model(hmt_model.through_model, hmt_model.name, nil)
120
+ return false
121
+ end
122
+ true
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,21 @@
1
+ class <%= class_name %> < ActiveRecord::Base
2
+ <% has_many_through_models.each do |hmt_model| -%>
3
+ <% attribs = Array.new(hmt_model.through_model.attributes) -%>
4
+ <% attribs << hmt_model.through_model.foreign_key_for(hmt_model.name) -%>
5
+ has_many :<%= hmt_model.name.underscore.pluralize %>, :through => :<%= hmt_model.through_model.name.underscore.pluralize %>
6
+ has_many :<%= hmt_model.through_model.name.underscore.pluralize %>
7
+ accepts_nested_attributes_for :<%= hmt_model.through_model.name.underscore.pluralize %>,
8
+ :allow_destroy => true<% if attribs.size > 0 %>,<% end %>
9
+ <% if attribs.size > 0 -%>
10
+ <% if attribs.size == 1 -%>
11
+ :reject_if => proc { |attrs| attrs['<%= attribs[0].name %>'].blank? }
12
+ <% elsif -%>
13
+ :reject_if => proc { |attrs|
14
+ <% attribs.each_with_index do |attr, i| -%>
15
+ attrs['<%= attr.name %>'].blank?<% unless i == attribs.size-1 %> &&<% end %>
16
+ <% end -%>
17
+ }
18
+ <% end -%>
19
+ <% end -%>
20
+ <% end -%>
21
+ end