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.
- data/Rakefile +5 -3
- data/VERSION +1 -1
- data/generators/view_for/view_for_generator.rb +4 -37
- data/lib/view_mapper/has_many_templates/controller.rb +85 -0
- data/lib/view_mapper/has_many_templates/fixtures.yml +19 -0
- data/lib/view_mapper/has_many_templates/functional_test.rb +45 -0
- data/lib/view_mapper/has_many_templates/helper.rb +18 -0
- data/lib/view_mapper/has_many_templates/helper_test.rb +4 -0
- data/lib/view_mapper/has_many_templates/layout.html.erb +19 -0
- data/lib/view_mapper/has_many_templates/migration.rb +16 -0
- data/lib/view_mapper/has_many_templates/model.rb +23 -0
- data/lib/view_mapper/has_many_templates/nested_attributes.js +13 -0
- data/lib/view_mapper/has_many_templates/style.css +58 -0
- data/lib/view_mapper/has_many_templates/unit_test.rb +8 -0
- data/lib/view_mapper/has_many_templates/view_child_form.html.erb +12 -0
- data/lib/view_mapper/has_many_templates/view_edit.html.erb +11 -0
- data/lib/view_mapper/has_many_templates/view_form.html.erb +20 -0
- data/lib/view_mapper/has_many_templates/view_index.html.erb +24 -0
- data/lib/view_mapper/has_many_templates/view_new.html.erb +10 -0
- data/lib/view_mapper/has_many_templates/view_show.html.erb +22 -0
- data/lib/view_mapper/has_many_view.rb +124 -0
- data/lib/view_mapper/model_info.rb +157 -0
- data/lib/view_mapper/paperclip_view.rb +5 -40
- data/lib/view_mapper/view_mapper.rb +2 -2
- data/lib/view_mapper.rb +2 -0
- data/test/expected_templates/has_many/_form.html.erb +26 -0
- data/test/expected_templates/has_many/_person.html.erb +18 -0
- data/test/expected_templates/has_many/create_parents.rb +15 -0
- data/test/expected_templates/has_many/edit.html.erb +11 -0
- data/test/expected_templates/has_many/index.html.erb +20 -0
- data/test/expected_templates/has_many/new.html.erb +10 -0
- data/test/expected_templates/has_many/parent.rb +14 -0
- data/test/expected_templates/has_many/show.html.erb +33 -0
- data/test/has_many_view_test.rb +405 -0
- data/test/model_info_test.rb +81 -0
- data/test/paperclip_view_test.rb +4 -27
- data/test/test_helper.rb +82 -9
- data/test/view_mapper_test.rb +2 -2
- data/view_mapper.gemspec +41 -5
- metadata +48 -5
data/Rakefile
CHANGED
@@ -5,14 +5,16 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "view_mapper"
|
8
|
-
gem.summary = %Q{
|
9
|
-
gem.description = %Q{
|
8
|
+
gem.summary = %Q{Scaffolding for your models and plugins}
|
9
|
+
gem.description = %Q{View_mapper will generate scaffolding for new or existing models, customized for the plugins you use in your app.}
|
10
10
|
gem.email = "pat@patshaughnessy.net"
|
11
|
-
gem.homepage = "http://
|
11
|
+
gem.homepage = "http://patshaughnessy.net/view_mapper"
|
12
12
|
gem.authors = ["Pat Shaughnessy"]
|
13
13
|
gem.add_development_dependency "thoughtbot-shoulda"
|
14
|
+
gem.add_development_dependency "mocha"
|
14
15
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
16
|
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
16
18
|
rescue LoadError
|
17
19
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
18
20
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
@@ -7,13 +7,10 @@ class ViewForGenerator < ScaffoldGenerator
|
|
7
7
|
attr_reader :model
|
8
8
|
attr_accessor :valid
|
9
9
|
|
10
|
-
BUILT_IN_COLUMNS = [ 'id', 'created_at', 'updated_at' ]
|
11
|
-
|
12
10
|
def initialize(runtime_args, runtime_options = {})
|
13
11
|
super
|
14
12
|
@source_root = source_root_for_view
|
15
|
-
|
16
|
-
@columns = custom_columns unless model.nil?
|
13
|
+
@model = ModelInfo.new(@name)
|
17
14
|
validate
|
18
15
|
end
|
19
16
|
|
@@ -21,31 +18,6 @@ class ViewForGenerator < ScaffoldGenerator
|
|
21
18
|
self.class.lookup('scaffold').path + "/templates"
|
22
19
|
end
|
23
20
|
|
24
|
-
def find_model(model_name)
|
25
|
-
@model = nil
|
26
|
-
begin
|
27
|
-
@model = Object.const_get model_name.camelize
|
28
|
-
if !model.new.kind_of? ActiveRecord::Base
|
29
|
-
logger.error "Class '#{model_name}' is not an ActiveRecord::Base."
|
30
|
-
@model = nil
|
31
|
-
end
|
32
|
-
rescue NameError
|
33
|
-
logger.error "Class '#{model_name}' does not exist or contains a syntax error and could not be loaded."
|
34
|
-
rescue ActiveRecord::StatementInvalid
|
35
|
-
logger.error "Table for model '#{model_name}' does not exist - run rake db:migrate first."
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def custom_columns
|
40
|
-
@model.columns.reject do |col|
|
41
|
-
built_in_columns.include? col.name
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def built_in_columns
|
46
|
-
BUILT_IN_COLUMNS
|
47
|
-
end
|
48
|
-
|
49
21
|
def record
|
50
22
|
EditableManifest.new(self) { |m| yield m }
|
51
23
|
end
|
@@ -69,17 +41,12 @@ class ViewForGenerator < ScaffoldGenerator
|
|
69
41
|
end
|
70
42
|
|
71
43
|
def attributes
|
72
|
-
@
|
73
|
-
end
|
74
|
-
|
75
|
-
def attributes_from_columns
|
76
|
-
@columns.collect do |col|
|
77
|
-
Rails::Generator::GeneratedAttribute.new col.name, col.type
|
78
|
-
end
|
44
|
+
@attributes ||= model.attributes
|
79
45
|
end
|
80
46
|
|
81
47
|
def validate
|
82
|
-
|
48
|
+
logger.error(model.error) if !model.valid?
|
49
|
+
@valid = model.valid?
|
83
50
|
end
|
84
51
|
|
85
52
|
def banner
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class <%= controller_class_name %>Controller < ApplicationController
|
2
|
+
# GET /<%= table_name %>
|
3
|
+
# GET /<%= table_name %>.xml
|
4
|
+
def index
|
5
|
+
@<%= table_name %> = <%= class_name %>.all
|
6
|
+
|
7
|
+
respond_to do |format|
|
8
|
+
format.html # index.html.erb
|
9
|
+
format.xml { render :xml => @<%= table_name %> }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /<%= table_name %>/1
|
14
|
+
# GET /<%= table_name %>/1.xml
|
15
|
+
def show
|
16
|
+
@<%= file_name %> = <%= class_name %>.find(params[:id])
|
17
|
+
|
18
|
+
respond_to do |format|
|
19
|
+
format.html # show.html.erb
|
20
|
+
format.xml { render :xml => @<%= file_name %> }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# GET /<%= table_name %>/new
|
25
|
+
# GET /<%= table_name %>/new.xml
|
26
|
+
def new
|
27
|
+
@<%= file_name %> = <%= class_name %>.new
|
28
|
+
|
29
|
+
respond_to do |format|
|
30
|
+
format.html # new.html.erb
|
31
|
+
format.xml { render :xml => @<%= file_name %> }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# GET /<%= table_name %>/1/edit
|
36
|
+
def edit
|
37
|
+
@<%= file_name %> = <%= class_name %>.find(params[:id])
|
38
|
+
end
|
39
|
+
|
40
|
+
# POST /<%= table_name %>
|
41
|
+
# POST /<%= table_name %>.xml
|
42
|
+
def create
|
43
|
+
@<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>])
|
44
|
+
|
45
|
+
respond_to do |format|
|
46
|
+
if @<%= file_name %>.save
|
47
|
+
flash[:notice] = '<%= class_name %> was successfully created.'
|
48
|
+
format.html { redirect_to(@<%= file_name %>) }
|
49
|
+
format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> }
|
50
|
+
else
|
51
|
+
format.html { render :action => "new" }
|
52
|
+
format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# PUT /<%= table_name %>/1
|
58
|
+
# PUT /<%= table_name %>/1.xml
|
59
|
+
def update
|
60
|
+
@<%= file_name %> = <%= class_name %>.find(params[:id])
|
61
|
+
|
62
|
+
respond_to do |format|
|
63
|
+
if @<%= file_name %>.update_attributes(params[:<%= file_name %>])
|
64
|
+
flash[:notice] = '<%= class_name %> was successfully updated.'
|
65
|
+
format.html { redirect_to(@<%= file_name %>) }
|
66
|
+
format.xml { head :ok }
|
67
|
+
else
|
68
|
+
format.html { render :action => "edit" }
|
69
|
+
format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# DELETE /<%= table_name %>/1
|
75
|
+
# DELETE /<%= table_name %>/1.xml
|
76
|
+
def destroy
|
77
|
+
@<%= file_name %> = <%= class_name %>.find(params[:id])
|
78
|
+
@<%= file_name %>.destroy
|
79
|
+
|
80
|
+
respond_to do |format|
|
81
|
+
format.html { redirect_to(<%= table_name %>_url) }
|
82
|
+
format.xml { head :ok }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
2
|
+
|
3
|
+
<% unless attributes.empty? -%>
|
4
|
+
one:
|
5
|
+
<% for attribute in attributes -%>
|
6
|
+
<%= attribute.name %>: <%= attribute.default %>
|
7
|
+
<% end -%>
|
8
|
+
|
9
|
+
two:
|
10
|
+
<% for attribute in attributes -%>
|
11
|
+
<%= attribute.name %>: <%= attribute.default %>
|
12
|
+
<% end -%>
|
13
|
+
<% else -%>
|
14
|
+
# one:
|
15
|
+
# column: value
|
16
|
+
#
|
17
|
+
# two:
|
18
|
+
# column: value
|
19
|
+
<% end -%>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class <%= controller_class_name %>ControllerTest < ActionController::TestCase
|
4
|
+
test "should get index" do
|
5
|
+
get :index
|
6
|
+
assert_response :success
|
7
|
+
assert_not_nil assigns(:<%= table_name %>)
|
8
|
+
end
|
9
|
+
|
10
|
+
test "should get new" do
|
11
|
+
get :new
|
12
|
+
assert_response :success
|
13
|
+
end
|
14
|
+
|
15
|
+
test "should create <%= file_name %>" do
|
16
|
+
assert_difference('<%= class_name %>.count') do
|
17
|
+
post :create, :<%= file_name %> => { }
|
18
|
+
end
|
19
|
+
|
20
|
+
assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
|
21
|
+
end
|
22
|
+
|
23
|
+
test "should show <%= file_name %>" do
|
24
|
+
get :show, :id => <%= table_name %>(:one).to_param
|
25
|
+
assert_response :success
|
26
|
+
end
|
27
|
+
|
28
|
+
test "should get edit" do
|
29
|
+
get :edit, :id => <%= table_name %>(:one).to_param
|
30
|
+
assert_response :success
|
31
|
+
end
|
32
|
+
|
33
|
+
test "should update <%= file_name %>" do
|
34
|
+
put :update, :id => <%= table_name %>(:one).to_param, :<%= file_name %> => { }
|
35
|
+
assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
|
36
|
+
end
|
37
|
+
|
38
|
+
test "should destroy <%= file_name %>" do
|
39
|
+
assert_difference('<%= class_name %>.count', -1) do
|
40
|
+
delete :destroy, :id => <%= table_name %>(:one).to_param
|
41
|
+
end
|
42
|
+
|
43
|
+
assert_redirected_to <%= table_name %>_path
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module <%= controller_class_name %>Helper
|
2
|
+
|
3
|
+
def remove_child_link(name, form_builder)
|
4
|
+
form_builder.hidden_field(:_delete) + link_to_function(name, "remove_child(this)")
|
5
|
+
end
|
6
|
+
|
7
|
+
def add_child_link(name, child, form_builder)
|
8
|
+
fields = escape_javascript(new_child_fields(child, form_builder))
|
9
|
+
link_to_function(name, h("add_child(this, \"#{child}\", \"#{fields}\")"))
|
10
|
+
end
|
11
|
+
|
12
|
+
def new_child_fields(child, form_builder)
|
13
|
+
form_builder.fields_for(child.pluralize.to_sym, child.camelize.constantize.new, :child_index => 'NEW_RECORD') do |f|
|
14
|
+
render(:partial => child.underscore, :locals => { :f => f })
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
+
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
5
|
+
<head>
|
6
|
+
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
|
7
|
+
<title><%= controller_class_name %>: <%%= controller.action_name %></title>
|
8
|
+
<%%= stylesheet_link_tag 'scaffold' %>
|
9
|
+
<%%= javascript_include_tag 'prototype.js' %>
|
10
|
+
<%%= javascript_include_tag 'nested_attributes.js' %>
|
11
|
+
</head>
|
12
|
+
<body>
|
13
|
+
|
14
|
+
<p style="color: green"><%%= flash[:notice] %></p>
|
15
|
+
|
16
|
+
<%%= yield %>
|
17
|
+
|
18
|
+
</body>
|
19
|
+
</html>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class <%= migration_name %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :<%= table_name %> do |t|
|
4
|
+
<% for attribute in attributes -%>
|
5
|
+
t.<%= attribute.type %> :<%= attribute.name %>
|
6
|
+
<% end -%>
|
7
|
+
<% unless options[:skip_timestamps] %>
|
8
|
+
t.timestamps
|
9
|
+
<% end -%>
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :<%= table_name %>
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class <%= class_name %> < ActiveRecord::Base
|
2
|
+
<% attributes.select(&:reference?).each do |attribute| -%>
|
3
|
+
belongs_to :<%= attribute.name %>
|
4
|
+
<% end -%>
|
5
|
+
<% child_models.each do |child_model| -%>
|
6
|
+
has_many :<%= child_model.name.underscore.pluralize %>
|
7
|
+
<% end -%>
|
8
|
+
<% child_models.each do |child_model| -%>
|
9
|
+
accepts_nested_attributes_for :<%= child_model.name.underscore.pluralize %>,
|
10
|
+
:allow_destroy => true<% if child_model.attributes.size > 0 %>,<% end %>
|
11
|
+
<% if child_model.attributes.size > 0 -%>
|
12
|
+
<% if child_model.attributes.size == 1 -%>
|
13
|
+
:reject_if => proc { |attrs| attrs['<%= child_model.attributes[0].name %>'].blank? }
|
14
|
+
<% elsif -%>
|
15
|
+
:reject_if => proc { |attrs|
|
16
|
+
<% child_model.attributes.each_with_index do |attr, i| -%>
|
17
|
+
attrs['<%= attr.name %>'].blank?<% unless i == child_model.attributes.size-1 %> &&<% end %>
|
18
|
+
<% end -%>
|
19
|
+
}
|
20
|
+
<% end -%>
|
21
|
+
<% end -%>
|
22
|
+
<% end -%>
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
function add_child(element, child_name, new_child) {
|
2
|
+
$(child_name + '_children').insert({
|
3
|
+
bottom: new_child.replace(/NEW_RECORD/g, new Date().getTime())
|
4
|
+
});
|
5
|
+
}
|
6
|
+
|
7
|
+
function remove_child(element) {
|
8
|
+
var hidden_field = $(element).previous("input[type=hidden]");
|
9
|
+
if (hidden_field) {
|
10
|
+
hidden_field.value = '1';
|
11
|
+
}
|
12
|
+
$(element).up(".child").hide();
|
13
|
+
}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
body { background-color: #fff; color: #333; }
|
2
|
+
|
3
|
+
body, p, ol, ul, td {
|
4
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
5
|
+
font-size: 13px;
|
6
|
+
line-height: 18px;
|
7
|
+
}
|
8
|
+
|
9
|
+
pre {
|
10
|
+
background-color: #eee;
|
11
|
+
padding: 10px;
|
12
|
+
font-size: 11px;
|
13
|
+
}
|
14
|
+
|
15
|
+
a { color: #000; }
|
16
|
+
a:visited { color: #666; }
|
17
|
+
a:hover { color: #fff; background-color:#000; }
|
18
|
+
|
19
|
+
.fieldWithErrors {
|
20
|
+
padding: 2px;
|
21
|
+
background-color: red;
|
22
|
+
display: table;
|
23
|
+
}
|
24
|
+
|
25
|
+
#errorExplanation {
|
26
|
+
width: 400px;
|
27
|
+
border: 2px solid red;
|
28
|
+
padding: 7px;
|
29
|
+
padding-bottom: 12px;
|
30
|
+
margin-bottom: 20px;
|
31
|
+
background-color: #f0f0f0;
|
32
|
+
}
|
33
|
+
|
34
|
+
#errorExplanation h2 {
|
35
|
+
text-align: left;
|
36
|
+
font-weight: bold;
|
37
|
+
padding: 5px 5px 5px 15px;
|
38
|
+
font-size: 12px;
|
39
|
+
margin: -7px;
|
40
|
+
background-color: #c00;
|
41
|
+
color: #fff;
|
42
|
+
}
|
43
|
+
|
44
|
+
#errorExplanation p {
|
45
|
+
color: #333;
|
46
|
+
margin-bottom: 0;
|
47
|
+
padding: 5px;
|
48
|
+
}
|
49
|
+
|
50
|
+
#errorExplanation ul li {
|
51
|
+
font-size: 12px;
|
52
|
+
list-style: square;
|
53
|
+
}
|
54
|
+
|
55
|
+
.child {
|
56
|
+
border-left: 10px solid #eee;
|
57
|
+
padding-left:10px;
|
58
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div class="child">
|
2
|
+
<% for attribute in child_model.attributes -%>
|
3
|
+
<p>
|
4
|
+
<%= child_model.name %> <%%= f.label :<%= attribute.name %> %><br />
|
5
|
+
<%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
|
6
|
+
</p>
|
7
|
+
<% end -%>
|
8
|
+
<p>
|
9
|
+
<%%= f.hidden_field :_delete, :class => 'delete' %>
|
10
|
+
<%%= remove_child_link 'remove', f %>
|
11
|
+
</p>
|
12
|
+
</div>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<h1>Editing <%= singular_name %></h1>
|
2
|
+
|
3
|
+
<%% form_for(@<%= singular_name %>) do |f| %>
|
4
|
+
<%%= render :partial => 'form', :locals => { :f => f } %>
|
5
|
+
<p>
|
6
|
+
<%%= f.submit 'Update' %>
|
7
|
+
</p>
|
8
|
+
<%% end %>
|
9
|
+
|
10
|
+
<%%= link_to 'Show', @<%= singular_name %> %> |
|
11
|
+
<%%= link_to 'Back', <%= plural_name %>_path %>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%%= f.error_messages %>
|
2
|
+
<% for attribute in attributes -%>
|
3
|
+
|
4
|
+
<p>
|
5
|
+
<%%= f.label :<%= attribute.name %> %><br />
|
6
|
+
<%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
|
7
|
+
</p>
|
8
|
+
<% end -%>
|
9
|
+
<% child_models.each do |child_model| -%>
|
10
|
+
|
11
|
+
<div id='<%= child_model.name.underscore %>_children'>
|
12
|
+
<%% f.fields_for :<%= child_model.name.underscore.pluralize %> do |<%= child_model.name.underscore %>_form| %>
|
13
|
+
<%%= render :partial => '<%= child_model.name.underscore %>', :locals => { :f => <%= child_model.name.underscore %>_form } %>
|
14
|
+
<%% end %>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<p>
|
18
|
+
<%%= add_child_link 'Add a <%= child_model.name %>', '<%= child_model.name.underscore %>', f %>
|
19
|
+
</p>
|
20
|
+
<% end -%>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<h1>Listing <%= plural_name %></h1>
|
2
|
+
|
3
|
+
<table>
|
4
|
+
<tr>
|
5
|
+
<% for attribute in attributes -%>
|
6
|
+
<th><%= attribute.column.human_name %></th>
|
7
|
+
<% end -%>
|
8
|
+
</tr>
|
9
|
+
|
10
|
+
<%% @<%= plural_name %>.each do |<%= singular_name %>| %>
|
11
|
+
<tr>
|
12
|
+
<% for attribute in attributes -%>
|
13
|
+
<td><%%=h <%= singular_name %>.<%= attribute.name %> %></td>
|
14
|
+
<% end -%>
|
15
|
+
<td><%%= link_to 'Show', <%= singular_name %> %></td>
|
16
|
+
<td><%%= link_to 'Edit', edit_<%= singular_name %>_path(<%= singular_name %>) %></td>
|
17
|
+
<td><%%= link_to 'Destroy', <%= singular_name %>, :confirm => 'Are you sure?', :method => :delete %></td>
|
18
|
+
</tr>
|
19
|
+
<%% end %>
|
20
|
+
</table>
|
21
|
+
|
22
|
+
<br />
|
23
|
+
|
24
|
+
<%%= link_to 'New <%= singular_name %>', new_<%= singular_name %>_path %>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<% for attribute in attributes -%>
|
2
|
+
<p>
|
3
|
+
<b><%= attribute.column.human_name %>:</b>
|
4
|
+
<%%=h @<%= singular_name %>.<%= attribute.name %> %>
|
5
|
+
</p>
|
6
|
+
|
7
|
+
<% end -%>
|
8
|
+
<% child_models.each do |child_model| -%>
|
9
|
+
<%% @<%= singular_name %>.<%= child_model.name.underscore.pluralize %>.each do |<%= child_model.name.underscore %>| %>
|
10
|
+
<div class="child">
|
11
|
+
<% for attribute in child_model.attributes -%>
|
12
|
+
<p>
|
13
|
+
<b><%= child_model.name %> <%= attribute.column.human_name %>:</b>
|
14
|
+
<%%=h <%= child_model.name.underscore%>.<%= attribute.name %> %>
|
15
|
+
</p>
|
16
|
+
<% end -%>
|
17
|
+
</div>
|
18
|
+
<%% end %>
|
19
|
+
|
20
|
+
<% end -%>
|
21
|
+
<%%= link_to 'Edit', edit_<%= singular_name %>_path(@<%= singular_name %>) %> |
|
22
|
+
<%%= link_to 'Back', <%= plural_name %>_path %>
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module ViewMapper
|
2
|
+
module HasManyView
|
3
|
+
|
4
|
+
attr_reader :child_models
|
5
|
+
|
6
|
+
def source_root_for_view
|
7
|
+
File.dirname(__FILE__) + "/has_many_templates"
|
8
|
+
end
|
9
|
+
|
10
|
+
def manifest
|
11
|
+
m = super.edit do |action|
|
12
|
+
action unless is_model_dependency_action(action) || is_view_show(action) || !valid
|
13
|
+
end
|
14
|
+
add_model_actions(m) if valid && !view_only?
|
15
|
+
if valid
|
16
|
+
m.template(
|
17
|
+
"view_show.html.erb",
|
18
|
+
File.join('app/views', controller_class_path, controller_file_name, "show.html.erb"),
|
19
|
+
{ :assigns => { :child_models => child_models } }
|
20
|
+
)
|
21
|
+
m.template(
|
22
|
+
"view_form.html.erb",
|
23
|
+
File.join('app/views', controller_class_path, controller_file_name, "_form.html.erb")
|
24
|
+
)
|
25
|
+
child_models.each do |child_model|
|
26
|
+
m.template(
|
27
|
+
"view_child_form.html.erb",
|
28
|
+
File.join('app/views', controller_class_path, controller_file_name, "_#{child_model.name.underscore}.html.erb"),
|
29
|
+
{ :assigns => { :child_model => child_model } }
|
30
|
+
|
31
|
+
)
|
32
|
+
end
|
33
|
+
m.file('nested_attributes.js', 'public/javascripts/nested_attributes.js')
|
34
|
+
end
|
35
|
+
m
|
36
|
+
end
|
37
|
+
|
38
|
+
def is_model_dependency_action(action)
|
39
|
+
action[0] == :dependency && action[1].include?('model')
|
40
|
+
end
|
41
|
+
|
42
|
+
def is_view_show(action)
|
43
|
+
action[0] == :template && action[1].include?('view_show.html.erb')
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_model_actions(m)
|
47
|
+
m.directory(File.join('test/fixtures', class_path))
|
48
|
+
m.template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb")
|
49
|
+
m.template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_test.rb")
|
50
|
+
unless options[:skip_fixture]
|
51
|
+
m.template 'fixtures.yml', File.join('test/fixtures', "#{table_name}.yml")
|
52
|
+
end
|
53
|
+
unless options[:skip_migration]
|
54
|
+
m.migration_template 'migration.rb',
|
55
|
+
'db/migrate',
|
56
|
+
:assigns => { :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}" },
|
57
|
+
:migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def child_models
|
62
|
+
@child_models ||= find_child_models
|
63
|
+
end
|
64
|
+
|
65
|
+
def find_child_models
|
66
|
+
if view_param
|
67
|
+
view_param.split(',').collect { |param| ModelInfo.new(param.singularize) }
|
68
|
+
elsif view_only?
|
69
|
+
model.child_models
|
70
|
+
else
|
71
|
+
[]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate
|
76
|
+
super
|
77
|
+
@valid &&= validate_child_models
|
78
|
+
end
|
79
|
+
|
80
|
+
def validate_child_models
|
81
|
+
cms = child_models
|
82
|
+
if cms.empty?
|
83
|
+
if view_only?
|
84
|
+
logger.error "No has_many associations exist in class #{model.name}."
|
85
|
+
else
|
86
|
+
logger.error "No has_many association specified."
|
87
|
+
end
|
88
|
+
return false
|
89
|
+
end
|
90
|
+
cms.reject! { |child_model| !validate_child_model(child_model) }
|
91
|
+
@child_models = cms
|
92
|
+
!cms.empty?
|
93
|
+
end
|
94
|
+
|
95
|
+
def validate_child_model(child_model)
|
96
|
+
if !child_model.valid?
|
97
|
+
logger.error child_model.error
|
98
|
+
return false
|
99
|
+
elsif view_only? && !model.accepts_nested_attributes_for?(child_model)
|
100
|
+
logger.warning "Model #{model.name} does not accept nested attributes for model #{child_model.name}."
|
101
|
+
return false
|
102
|
+
else
|
103
|
+
if child_model.has_many?(class_name.pluralize) || child_model.has_and_belongs_to_many?(class_name.pluralize)
|
104
|
+
true
|
105
|
+
elsif !child_model.belongs_to?(class_name)
|
106
|
+
logger.warning "Model #{child_model.name} does not contain a belongs_to association for #{class_name}."
|
107
|
+
return false
|
108
|
+
elsif !child_model.has_foreign_key_for?(class_name)
|
109
|
+
logger.warning "Model #{child_model.name} does not contain a foreign key for #{class_name}."
|
110
|
+
return false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
true
|
114
|
+
end
|
115
|
+
|
116
|
+
def validate_child_model_associations(child_model)
|
117
|
+
if child_model.belongs_to?(class_name)
|
118
|
+
true
|
119
|
+
else
|
120
|
+
child_model.has_many?(class_name.pluralize) || child_model.has_and_belongs_to_many?(class_name.pluralize)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|