view_mapper 0.2.0 → 0.3.0

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 (40) hide show
  1. data/Rakefile +5 -3
  2. data/VERSION +1 -1
  3. data/generators/view_for/view_for_generator.rb +4 -37
  4. data/lib/view_mapper/has_many_templates/controller.rb +85 -0
  5. data/lib/view_mapper/has_many_templates/fixtures.yml +19 -0
  6. data/lib/view_mapper/has_many_templates/functional_test.rb +45 -0
  7. data/lib/view_mapper/has_many_templates/helper.rb +18 -0
  8. data/lib/view_mapper/has_many_templates/helper_test.rb +4 -0
  9. data/lib/view_mapper/has_many_templates/layout.html.erb +19 -0
  10. data/lib/view_mapper/has_many_templates/migration.rb +16 -0
  11. data/lib/view_mapper/has_many_templates/model.rb +23 -0
  12. data/lib/view_mapper/has_many_templates/nested_attributes.js +13 -0
  13. data/lib/view_mapper/has_many_templates/style.css +58 -0
  14. data/lib/view_mapper/has_many_templates/unit_test.rb +8 -0
  15. data/lib/view_mapper/has_many_templates/view_child_form.html.erb +12 -0
  16. data/lib/view_mapper/has_many_templates/view_edit.html.erb +11 -0
  17. data/lib/view_mapper/has_many_templates/view_form.html.erb +20 -0
  18. data/lib/view_mapper/has_many_templates/view_index.html.erb +24 -0
  19. data/lib/view_mapper/has_many_templates/view_new.html.erb +10 -0
  20. data/lib/view_mapper/has_many_templates/view_show.html.erb +22 -0
  21. data/lib/view_mapper/has_many_view.rb +124 -0
  22. data/lib/view_mapper/model_info.rb +157 -0
  23. data/lib/view_mapper/paperclip_view.rb +5 -40
  24. data/lib/view_mapper/view_mapper.rb +2 -2
  25. data/lib/view_mapper.rb +2 -0
  26. data/test/expected_templates/has_many/_form.html.erb +26 -0
  27. data/test/expected_templates/has_many/_person.html.erb +18 -0
  28. data/test/expected_templates/has_many/create_parents.rb +15 -0
  29. data/test/expected_templates/has_many/edit.html.erb +11 -0
  30. data/test/expected_templates/has_many/index.html.erb +20 -0
  31. data/test/expected_templates/has_many/new.html.erb +10 -0
  32. data/test/expected_templates/has_many/parent.rb +14 -0
  33. data/test/expected_templates/has_many/show.html.erb +33 -0
  34. data/test/has_many_view_test.rb +405 -0
  35. data/test/model_info_test.rb +81 -0
  36. data/test/paperclip_view_test.rb +4 -27
  37. data/test/test_helper.rb +82 -9
  38. data/test/view_mapper_test.rb +2 -2
  39. data/view_mapper.gemspec +41 -5
  40. metadata +48 -5
@@ -0,0 +1,157 @@
1
+ module ViewMapper
2
+ class ModelInfo
3
+
4
+ attr_reader :model
5
+ attr_reader :name
6
+ attr_reader :attributes
7
+ attr_reader :error
8
+
9
+ def initialize(model_name)
10
+ @model = find_model(model_name)
11
+ @name = model.to_s unless model.nil?
12
+ end
13
+
14
+ def valid?
15
+ error.nil?
16
+ end
17
+
18
+ def columns
19
+ @columns ||= active_record_columns.collect { |col| col.name }
20
+ end
21
+
22
+ def attributes
23
+ @attributes ||= active_record_columns.collect { |col| Rails::Generator::GeneratedAttribute.new col.name, col.type }
24
+ end
25
+
26
+ def attachments
27
+ @attachments = find_attachments
28
+ end
29
+
30
+ def has_attachment?(attachment)
31
+ attachments.include?(attachment)
32
+ end
33
+
34
+ def has_columns_for_attachment?(attachment)
35
+ !paperclip_columns_for_attachment(attachment).detect { |paperclip_col| !has_column_for_attachment(attachment, paperclip_col) }
36
+ end
37
+
38
+ def child_models
39
+ model.reflections.select { |key, value| value.macro == :has_many }.collect do |kvpair|
40
+ kvpair[0].to_s.singularize
41
+ end.sort.collect do |model_name|
42
+ ModelInfo.new model_name
43
+ end
44
+ end
45
+
46
+ def accepts_nested_attributes_for?(child_model)
47
+ if !model.new.methods.include? "#{child_model.name.underscore.pluralize}_attributes="
48
+ @error = "Model #{model} does not accept nested attributes for model #{child_model.name}."
49
+ false
50
+ else
51
+ true
52
+ end
53
+ end
54
+
55
+ def belongs_to?(parent_model_name)
56
+ has_association_for? :belongs_to, parent_model_name
57
+ end
58
+
59
+ def has_many?(child_model_name)
60
+ has_association_for? :has_many, child_model_name
61
+ end
62
+
63
+ def has_and_belongs_to_many?(model_name)
64
+ has_association_for? :has_and_belongs_to_many, model_name
65
+ end
66
+
67
+ def has_foreign_key_for?(parent_model_name)
68
+ model.columns.detect { |col| is_foreign_key_for?(col, parent_model_name) }
69
+ end
70
+
71
+ private
72
+
73
+ def find_model(model_name)
74
+ model = nil
75
+ begin
76
+ model = Object.const_get model_name.camelize
77
+ if !model.new.kind_of? ActiveRecord::Base
78
+ @error = "Class '#{model_name}' is not an ActiveRecord::Base."
79
+ model = nil
80
+ end
81
+ rescue NameError
82
+ @error = "Class '#{model_name}' does not exist or contains a syntax error and could not be loaded."
83
+ rescue ActiveRecord::StatementInvalid
84
+ @error = "Table for model '#{model_name}' does not exist - run rake db:migrate first."
85
+ end
86
+ model
87
+ end
88
+
89
+ def active_record_columns
90
+ @active_record_columns ||= inspect_active_record_columns
91
+ end
92
+
93
+ def inspect_active_record_columns
94
+ model.columns.reject do |col|
95
+ is_timestamp?(col) || is_primary_key?(col) || is_foreign_key?(col) || is_paperclip_column?(col)
96
+ end
97
+ end
98
+
99
+ def is_timestamp?(col)
100
+ %w{ updated_at updated_on created_at created_on }.include? col.name
101
+ end
102
+
103
+ def is_primary_key?(col)
104
+ col.name == model.primary_key
105
+ end
106
+
107
+ def is_foreign_key?(col)
108
+ model.reflections.values.detect do |reflection|
109
+ col.name == reflection.primary_key_name
110
+ end
111
+ end
112
+
113
+ def is_foreign_key_for?(col, parent_model_name)
114
+ model.reflections.values.detect do |reflection|
115
+ col.name == reflection.primary_key_name && reflection.name == parent_model_name.underscore.to_sym
116
+ end
117
+ end
118
+
119
+ def has_association_for?(association, model_name)
120
+ !model.reflections.values.detect do |reflection|
121
+ reflection.name == model_name.underscore.to_sym && reflection.macro == association
122
+ end.nil?
123
+ end
124
+
125
+ def is_paperclip_column?(col)
126
+ paperclip_columns.include?(col.name)
127
+ end
128
+
129
+ def find_attachments
130
+ if model.respond_to?('attachment_definitions') && model.attachment_definitions
131
+ model.attachment_definitions.keys.collect(&:to_s).sort
132
+ else
133
+ []
134
+ end
135
+ end
136
+
137
+ def has_column_for_attachment(attachment, paperclip_col)
138
+ has_column = model.columns.map {|col| col.name}.include?(paperclip_col)
139
+ if !has_column
140
+ @error = "Column \'#{paperclip_col}\' does not exist. First run script/generate paperclip #{name.downcase} #{attachment}."
141
+ end
142
+ has_column
143
+ end
144
+
145
+ def paperclip_columns
146
+ @paperclip_columns ||= attachments.inject([]) do |result, element|
147
+ result + paperclip_columns_for_attachment(element)
148
+ end
149
+ end
150
+
151
+ def paperclip_columns_for_attachment(attachment)
152
+ %w{ file_name content_type file_size updated_at }.collect do |col|
153
+ "#{attachment}_#{col}"
154
+ end
155
+ end
156
+ end
157
+ end
@@ -38,7 +38,7 @@ module ViewMapper
38
38
  if view_param
39
39
  parse_attachments_from_param
40
40
  elsif view_only?
41
- inspect_model_for_attachments
41
+ model.attachments
42
42
  else
43
43
  []
44
44
  end
@@ -48,14 +48,6 @@ module ViewMapper
48
48
  view_param.split(',')
49
49
  end
50
50
 
51
- def inspect_model_for_attachments
52
- if model.respond_to?('attachment_definitions') && model.attachment_definitions
53
- model.attachment_definitions.keys.collect { |name| name.to_s }.sort
54
- else
55
- []
56
- end
57
- end
58
-
59
51
  def validate
60
52
  @valid = validate_attachments
61
53
  @valid &&= super
@@ -65,7 +57,7 @@ module ViewMapper
65
57
  if !paperclip_installed
66
58
  logger.error "The Paperclip plugin does not appear to be installed."
67
59
  return false
68
- elsif attachments == []
60
+ elsif attachments.empty?
69
61
  if view_only?
70
62
  logger.warning "No paperclip attachments exist on the specified class."
71
63
  else
@@ -79,44 +71,17 @@ module ViewMapper
79
71
 
80
72
  def validate_attachment(attachment)
81
73
  if view_only?
82
- if !has_attachment(attachment.to_sym)
74
+ if !model.has_attachment?(attachment)
83
75
  logger.error "Attachment '#{attachment}' does not exist."
84
76
  return false
85
- elsif !has_columns_for_attachment(attachment)
77
+ elsif !model.has_columns_for_attachment?(attachment)
78
+ logger.error model.error
86
79
  return false
87
80
  end
88
81
  end
89
82
  true
90
83
  end
91
84
 
92
- def has_attachment(attachment)
93
- model.attachment_definitions && model.attachment_definitions.has_key?(attachment)
94
- end
95
-
96
- def has_columns_for_attachment(attachment)
97
- !paperclip_columns_for_attachment(attachment).detect { |paperclip_col| !has_column_for_attachment(attachment, paperclip_col) }
98
- end
99
-
100
- def has_column_for_attachment(attachment, paperclip_col)
101
- has_column = model.columns.collect { |col| col.name }.include?(paperclip_col)
102
- if !has_column
103
- logger.error "Column \'#{paperclip_col}\' does not exist. First run script/generate paperclip #{name} #{attachment}."
104
- end
105
- has_column
106
- end
107
-
108
- def built_in_columns
109
- attachments.inject(super) do |result, element|
110
- result + paperclip_columns_for_attachment(element)
111
- end
112
- end
113
-
114
- def paperclip_columns_for_attachment(attachment)
115
- %w{ file_name content_type file_size updated_at }.collect do |col|
116
- "#{attachment}_#{col}"
117
- end
118
- end
119
-
120
85
  def paperclip_installed
121
86
  ActiveRecord::Base.methods.include? 'has_attached_file'
122
87
  end
@@ -6,12 +6,12 @@ module ViewMapper
6
6
  Rails::Generator::Commands::Destroy.class_eval { include RouteAction::Destroy }
7
7
  super
8
8
  if options[:view]
9
- self.extend(view_class)
9
+ self.extend(view_module)
10
10
  @source_root = source_root_for_view
11
11
  end
12
12
  end
13
13
 
14
- def view_class
14
+ def view_module
15
15
  "ViewMapper::#{view_name.camelize}View".constantize
16
16
  end
17
17
 
data/lib/view_mapper.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'view_mapper/auto_complete_view'
2
2
  require 'view_mapper/paperclip_view'
3
+ require 'view_mapper/has_many_view'
3
4
  require 'view_mapper/route_action'
4
5
  require 'view_mapper/editable_manifest'
6
+ require 'view_mapper/model_info'
5
7
  require 'view_mapper/view_mapper'
@@ -0,0 +1,26 @@
1
+ <%= f.error_messages %>
2
+
3
+ <p>
4
+ <%= f.label :name %><br />
5
+ <%= f.text_field :name %>
6
+ </p>
7
+
8
+ <div id='some_other_model_children'>
9
+ <% f.fields_for :some_other_models do |some_other_model_form| %>
10
+ <%= render :partial => 'some_other_model', :locals => { :f => some_other_model_form } %>
11
+ <% end %>
12
+ </div>
13
+
14
+ <p>
15
+ <%= add_child_link 'Add a SomeOtherModel', 'some_other_model', f %>
16
+ </p>
17
+
18
+ <div id='testy_children'>
19
+ <% f.fields_for :testies do |testy_form| %>
20
+ <%= render :partial => 'testy', :locals => { :f => testy_form } %>
21
+ <% end %>
22
+ </div>
23
+
24
+ <p>
25
+ <%= add_child_link 'Add a Testy', 'testy', f %>
26
+ </p>
@@ -0,0 +1,18 @@
1
+ <div class="child">
2
+ <p>
3
+ Testy <%= f.label :first_name %><br />
4
+ <%= f.text_field :first_name %>
5
+ </p>
6
+ <p>
7
+ Testy <%= f.label :last_name %><br />
8
+ <%= f.text_field :last_name %>
9
+ </p>
10
+ <p>
11
+ Testy <%= f.label :address %><br />
12
+ <%= f.text_field :address %>
13
+ </p>
14
+ <p>
15
+ <%= f.hidden_field :_delete, :class => 'delete' %>
16
+ <%= remove_child_link 'remove', f %>
17
+ </p>
18
+ </div>
@@ -0,0 +1,15 @@
1
+ class CreateParents < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :parents do |t|
4
+ t.string :first_name
5
+ t.string :last_name
6
+ t.string :address
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :parents
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ <h1>Editing parent</h1>
2
+
3
+ <% form_for(@parent) do |f| %>
4
+ <%= render :partial => 'form', :locals => { :f => f } %>
5
+ <p>
6
+ <%= f.submit 'Update' %>
7
+ </p>
8
+ <% end %>
9
+
10
+ <%= link_to 'Show', @parent %> |
11
+ <%= link_to 'Back', parents_path %>
@@ -0,0 +1,20 @@
1
+ <h1>Listing parents</h1>
2
+
3
+ <table>
4
+ <tr>
5
+ <th>Name</th>
6
+ </tr>
7
+
8
+ <% @parents.each do |parent| %>
9
+ <tr>
10
+ <td><%=h parent.name %></td>
11
+ <td><%= link_to 'Show', parent %></td>
12
+ <td><%= link_to 'Edit', edit_parent_path(parent) %></td>
13
+ <td><%= link_to 'Destroy', parent, :confirm => 'Are you sure?', :method => :delete %></td>
14
+ </tr>
15
+ <% end %>
16
+ </table>
17
+
18
+ <br />
19
+
20
+ <%= link_to 'New parent', new_parent_path %>
@@ -0,0 +1,10 @@
1
+ <h1>New parent</h1>
2
+
3
+ <% form_for(@parent) do |f| %>
4
+ <%= render :partial => 'form', :locals => { :f => f } %>
5
+ <p>
6
+ <%= f.submit 'Create' %>
7
+ </p>
8
+ <% end %>
9
+
10
+ <%= link_to 'Back', parents_path %>
@@ -0,0 +1,14 @@
1
+ class Parent < ActiveRecord::Base
2
+ has_many :some_other_models
3
+ has_many :testies
4
+ accepts_nested_attributes_for :some_other_models,
5
+ :allow_destroy => true,
6
+ :reject_if => proc { |attrs| attrs['name'].blank? }
7
+ accepts_nested_attributes_for :testies,
8
+ :allow_destroy => true,
9
+ :reject_if => proc { |attrs|
10
+ attrs['first_name'].blank? &&
11
+ attrs['last_name'].blank? &&
12
+ attrs['address'].blank?
13
+ }
14
+ end
@@ -0,0 +1,33 @@
1
+ <p>
2
+ <b>Name:</b>
3
+ <%=h @parent.name %>
4
+ </p>
5
+
6
+ <% @parent.some_other_models.each do |some_other_model| %>
7
+ <div class="child">
8
+ <p>
9
+ <b>SomeOtherModel Name:</b>
10
+ <%=h some_other_model.name %>
11
+ </p>
12
+ </div>
13
+ <% end %>
14
+
15
+ <% @parent.testies.each do |testy| %>
16
+ <div class="child">
17
+ <p>
18
+ <b>Testy First name:</b>
19
+ <%=h testy.first_name %>
20
+ </p>
21
+ <p>
22
+ <b>Testy Last name:</b>
23
+ <%=h testy.last_name %>
24
+ </p>
25
+ <p>
26
+ <b>Testy Address:</b>
27
+ <%=h testy.address %>
28
+ </p>
29
+ </div>
30
+ <% end %>
31
+
32
+ <%= link_to 'Edit', edit_parent_path(@parent) %> |
33
+ <%= link_to 'Back', parents_path %>