crud 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +1 -0
  3. data/LICENSE.md +674 -0
  4. data/README.md +136 -0
  5. data/Rakefile +72 -0
  6. data/app/assets/images/crud/search-icon.png +0 -0
  7. data/app/assets/javascripts/crud/application.js +17 -0
  8. data/app/assets/javascripts/crud/dashboard.js +7 -0
  9. data/app/assets/javascripts/crud/pagination.js +41 -0
  10. data/app/assets/stylesheets/crud/application.css +27 -0
  11. data/app/assets/stylesheets/crud/dashboard.css +4 -0
  12. data/app/assets/stylesheets/crud/flash_notices.css +19 -0
  13. data/app/assets/stylesheets/crud/pagination.css +104 -0
  14. data/app/assets/stylesheets/dataTables/jquery.dataTables-override.css +20 -0
  15. data/app/controllers/crud/crud_base_controller.rb +28 -0
  16. data/app/controllers/crud/crud_controller.rb +149 -0
  17. data/app/controllers/crud/dashboard_controller.rb +17 -0
  18. data/app/helpers/crud/crud_helper.rb +104 -0
  19. data/app/helpers/crud/dashboard_helper.rb +4 -0
  20. data/app/models/crud/klass_info.rb +166 -0
  21. data/app/models/crud/klass_list.rb +51 -0
  22. data/app/models/crud/menus/development_menu.rb +63 -0
  23. data/app/views/crud/crud/_attribute_value.html.erb +5 -0
  24. data/app/views/crud/crud/_error_messages.html.erb +10 -0
  25. data/app/views/crud/crud/_flash_messages.html.erb +10 -0
  26. data/app/views/crud/crud/_form.html.erb +22 -0
  27. data/app/views/crud/crud/_klass_data.html.erb +117 -0
  28. data/app/views/crud/crud/edit.html.erb +17 -0
  29. data/app/views/crud/crud/index.html.erb +6 -0
  30. data/app/views/crud/crud/index.js.erb +1 -0
  31. data/app/views/crud/crud/new.html.erb +13 -0
  32. data/app/views/crud/crud/show.html.erb +69 -0
  33. data/app/views/crud/dashboard/index.html.erb +15 -0
  34. data/app/views/layouts/crud/application.html.erb +13 -0
  35. data/config/cucumber.yml +8 -0
  36. data/config/initializers/inflections.rb +5 -0
  37. data/config/initializers/rails_engine.rb +8 -0
  38. data/config/initializers/will_paginate.rb +1 -0
  39. data/config/locales/de.yml +3 -0
  40. data/config/locales/en.yml +3 -0
  41. data/config/locales/es.yml +3 -0
  42. data/config/locales/fr.yml +3 -0
  43. data/config/routes.rb +16 -0
  44. data/crud.gemspec +29 -0
  45. data/lib/crud.rb +144 -0
  46. data/lib/crud/engine.rb +23 -0
  47. data/lib/crud/version.rb +3 -0
  48. data/lib/tasks/crud_tasks.rake +4 -0
  49. metadata +157 -0
@@ -0,0 +1,51 @@
1
+ # Processor to create a list of models
2
+ module Crud
3
+ class KlassList
4
+ def initialize
5
+ update
6
+ end
7
+
8
+ def update
9
+ #return if $all_klasses
10
+ all_model_names = []
11
+ ::Crud.model_path.each do |path_element|
12
+ model_files = Dir[ File.join(path_element, '**', '*.rb').to_s ]
13
+ model_names = model_files.map { |item| item.sub(path_element,'').sub(/^\//,'').sub(/\.rb$/,'').camelize.gsub(File::SEPARATOR,'::') }
14
+ all_model_names += model_names
15
+ end
16
+
17
+ klasses = create_klasses_from_model_names(all_model_names)
18
+ #Rails.logger.debug "create_klasses_from_model_names()"
19
+ #klasses.each {|klass| Rails.logger.debug "#{klass}"}
20
+
21
+ $all_klasses = remove_klasses_without_table(klasses).sort_by {|r| r.name.underscore}
22
+ Rails.logger.debug "$all_klasses"
23
+ $all_klasses.each {|klass| Rails.logger.debug "#{klass} (#{klass.name.underscore})"}
24
+ end
25
+
26
+ def all
27
+ $all_klasses
28
+ end
29
+
30
+ private
31
+
32
+ def create_klasses_from_model_names(model_names)
33
+ model_names.inject([]) do |output, model_name|
34
+ klass_name = model_name
35
+ begin
36
+ klass = klass_name.constantize
37
+ output << "::#{klass}".constantize if klass_name == klass.to_s
38
+ rescue Exception => e
39
+ Rails.logger.debug e.message
40
+ end
41
+ output
42
+ end
43
+ end
44
+
45
+ def remove_klasses_without_table(klasses)
46
+ klasses.select { |klass| klass.ancestors.include?(ActiveRecord::Base) && klass.connection.table_exists?(klass.table_name) }
47
+ end
48
+ end
49
+ end
50
+
51
+ # p.to_s if p.respond_to?(:to_s) && /^<.+>$/.match(p.to_s).nil?
@@ -0,0 +1,63 @@
1
+ # Development Menu
2
+ module Crud
3
+ class Menus::DevelopmentMenu < Hash
4
+ def initialize
5
+ root_dir = Crud::Engine.root
6
+
7
+ Dir.glob( File.join(root_dir, 'app', 'controllers', '**', '*_controller.rb') ).sort.each do |controller_file|
8
+ controller_prefix = File.dirname( controller_file.gsub(/^.*controllers/, "").gsub(/^[\\\/]/, "") )
9
+ controller_prefix = (controller_prefix.length == 1) ? '' : controller_prefix + '/'
10
+ controller = File.basename(controller_file, ".rb")
11
+ controller_object = controller.camelize
12
+
13
+ model_prefix = controller_prefix.gsub(/^.*admin/,"").gsub(/^[\\\/]/, "")
14
+ model = controller.gsub("_controller","").singularize
15
+ model_object = model.camelize
16
+
17
+ if File.exist?( File.join(root_dir, 'app', 'models', model_prefix, model + '.rb') )
18
+ next if ['report'].include?(model)
19
+
20
+ #link_text = t(model + '.object_name').to_s.humanize
21
+ #link_text = t(model + '.object_name').to_s.humanize.pluralize
22
+ link_text = model.to_s.humanize.pluralize
23
+ controller_for_url = "#{controller_prefix}#{controller.gsub("_controller","")}"
24
+ action_for_url = 'index'
25
+
26
+ # Initialise section reference
27
+ section = self
28
+
29
+ controller_prefix.split(File::SEPARATOR).each do |sub_section|
30
+ if section[sub_section].nil?
31
+ section[sub_section] = Hash.new
32
+ #section[sub_section]['name'] = sub_section.to_s.humanize
33
+ end
34
+ section = section[sub_section]
35
+ end
36
+
37
+ section = Hash.new if section.nil?
38
+ section[controller] = Hash.new if section[controller].nil?
39
+ section[controller]['name'] = link_text
40
+ section[controller]['controller'] = controller_for_url
41
+ section[controller]['action'] = action_for_url
42
+ end
43
+ end
44
+ end
45
+
46
+ def depth(menu = self, count = 0)
47
+ count += 1
48
+
49
+ menu.each do |key, value|
50
+ break if value.class != Hash || value.has_key?('controller')
51
+
52
+ tmp_depth = depth(value, count)
53
+ count = tmp_depth if tmp_depth > count
54
+ end
55
+
56
+ count
57
+ end
58
+
59
+ def items
60
+ self
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,5 @@
1
+ <% # Parameters :attribute => attribute, :klass_data => row_data %>
2
+ <%#= #render_attribute_value(attribute, klass_data) %>
3
+ <%#= #render_custom_fields(attribute, klass_data, @klass_info) %>
4
+
5
+ <%= render_attribute_value_and_custom_fields(attribute, klass_data, @klass_info) %>
@@ -0,0 +1,10 @@
1
+ <% if model && model.errors.any? %>
2
+ <div id="error_explanation">
3
+ <h2><%= pluralize(model.errors.count, "error") %> prohibited this <%= model.to_s %> from being saved:</h2>
4
+ <ul>
5
+ <% model.errors.full_messages.each do |message| %>
6
+ <li><%=message%></li>
7
+ <% end %>
8
+ </ul>
9
+ </div>
10
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <%= stylesheet_link_tag 'crud/flash_notices', :media => 'screen' %>
2
+ <div class="clearthis">&nbsp;</div>
3
+ <% flash.each do |type, value| %>
4
+ <% unless flash.now[type.to_sym].blank? %>
5
+ <div id='flash-<%="#{type.to_s}"%>' class='flash_message flash_<%="#{type.to_s}"%>' >
6
+ <p><%= "#{value}" %></p>
7
+ </div>
8
+ <div class="clearthis">&nbsp;</div>
9
+ <% end %>
10
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <%= render 'error_messages', :model => @klass_data %>
2
+ <div class="actions">
3
+ <%= f.submit %>
4
+ </div>
5
+ <% @visible_attributes.each do |attribute| %>
6
+ <% unless ['id','created_at', 'updated_at'].include?(attribute[:column_name]) %>
7
+ <div class="field">
8
+ <%= f.label attribute[:column_name].to_sym %><br />
9
+ <% custom_fields = @klass_info.custom_fields(attribute[:column_name], controller.action_name.to_sym) %>
10
+ <% custom_fields_contain_a_replacement = @klass_info.custom_fields_contain_a_replacement(custom_fields) %>
11
+ <% unless custom_fields_contain_a_replacement %>
12
+ <%= edit_field_for_attribute(@klass_info, @klass_data, attribute, f).html_safe %>
13
+ <% end %>
14
+ <% custom_fields.each do |field| %>
15
+ <%= render field[:partial], {field[:record_data_parameter].to_sym => @klass_data}.merge(field[:additional_partial_parameters]) %><br/>
16
+ <% end %>
17
+ </div>
18
+ <% end %>
19
+ <% end %>
20
+ <div class="actions">
21
+ <%= f.submit %>
22
+ </div>
@@ -0,0 +1,117 @@
1
+ <div style="clear: both;"/>
2
+ <br />
3
+
4
+ <div style="clear: both;"/>
5
+ <% if is_allowed_to_update? %>
6
+ <%= link_to "New #{@klass_info[:name]}", new_path(:class_name => @klass_info[:name]) %>
7
+ <% end %>
8
+
9
+ <div style="clear: both;"/>
10
+ <br />
11
+
12
+ <div style="clear: both;"/>
13
+ <div id="crud_pagination" class="flickr_pagination" style="text-align: left; float: left; width: 75%;">
14
+ Items per page:
15
+ <%= select_tag :per_page, options_for_select([5, 10, 25, 50, 100], (controller.params[:per_page] ? controller.params[:per_page].to_i : 10)) %>
16
+ <br /><br />
17
+ <div id="upper_pagination_overlay" class="pagination_overlay" style="height: 16px;">
18
+ <%= will_paginate @klass_data %>
19
+ <%= hidden_field_tag :page, (controller.params[:page] ? controller.params[:page] : 1) %>
20
+ </div>
21
+ <br />
22
+ <%= page_entries_info @klass_data %>
23
+ <br /><br />
24
+ </div>
25
+ <div id="crud_search" style="text-align: right; float: right; width: 20%; min-width: 250px;">
26
+ <%= form_tag '#', :id => 'search_form', :method => :get do %>
27
+ Search:
28
+ <%= text_field_tag :search, ((controller.params[:search].nil? || controller.params[:search].empty?) ? @search_prompt : controller.params[:search]),
29
+ :value => ((controller.params[:search].nil? || controller.params[:search].empty?) ? @search_prompt : controller.params[:search]),
30
+ :style => ((controller.params[:search].nil? || controller.params[:search].empty?) ? 'color:#777;' : ''),
31
+ :onfocus => "if(this.value == '#{@search_prompt}') {this.style.color=''; this.value = '';}",
32
+ :onblur => "if(this.value == '') {this.style.color='#777'; this.value = '#{@search_prompt}';}"
33
+ -%>
34
+ <%= image_submit_tag 'crud/search-icon.png', { :height => '16' } %>
35
+ <br />
36
+ <% if false %>
37
+ <%= check_box_tag :crud_advanced_search, nil, ((controller.params[:advanced_search]=='true') ? true : false) %> <%= I18n.t(:advanced_search_prompt) %>
38
+ <% end %>
39
+ <% end %>
40
+ </div>
41
+ <div style="clear: both;"/>
42
+ <br />
43
+
44
+ <% if @klass_data.count > 0 %>
45
+ <table id="klass_table">
46
+ <thead>
47
+ <tr>
48
+ <% if false %>
49
+ <th></th>
50
+ <% end %>
51
+ <% @visible_attributes.each do |attribute| %>
52
+ <th>
53
+ <%= label(@klass_info[:name].to_sym, attribute[:column_name].to_sym) %>
54
+ <% if false %>
55
+ <%= "(#{attribute[:column_type]})" %>
56
+ <%= "#{attribute[:association].to_s} #{attribute[:association_class]}" if attribute[:association] %>
57
+ <% end %>
58
+ </th>
59
+ <% end %>
60
+ <% if is_allowed_to_view? %>
61
+ <th></th>
62
+ <% end %>
63
+ <% if is_allowed_to_update? %>
64
+ <th></th>
65
+ <th></th>
66
+ <th></th>
67
+ <% end %>
68
+ </tr>
69
+ </thead>
70
+ <tbody>
71
+ <% @klass_data.each do |row| %>
72
+ <tr style="background-color:<%= cycle("lightblue", "lightgrey") %>;">
73
+ <% if false %>
74
+ <td><%= check_box 'selected_items', row.attributes['id'], :id => nil %></td>
75
+ <% end %>
76
+ <% @visible_attributes.each do |attribute| %>
77
+ <td>
78
+ <%= render_attribute_value_and_custom_fields(attribute, row, @klass_info) %>
79
+ </td>
80
+ <% end %>
81
+ <% if is_allowed_to_view? %>
82
+ <td><%= link_to('Show', show_path(:class_name => @klass_info[:name], :id => row.id)) if ::Crud::KlassInfo.primary_key_is_id?(@klass_info[:class]) %></td>
83
+ <% end %>
84
+ <% if is_allowed_to_update? %>
85
+ <td><%= link_to('Edit', edit_path(:class_name => @klass_info[:name], :id => row.id)) if ::Crud::KlassInfo.primary_key_is_id?(@klass_info[:class]) %></td>
86
+ <td><%= link_to('Delete', delete_path(:class_name => @klass_info[:name], :id => row.id), :data => { :confirm => "Are you sure you want to delete '#{row}'?" }, :method => :delete) if ::Crud::KlassInfo.primary_key_is_id?(@klass_info[:class]) %></td>
87
+ <td><%= link_to('Destroy', destroy_path(:class_name => @klass_info[:name], :id => row.id), :data => { :confirm => "Are you sure you want to destroy '#{row}'?" }, :method => :delete) if ::Crud::KlassInfo.primary_key_is_id?(@klass_info[:class]) %></td>
88
+ <% end %>
89
+ </tr>
90
+ <% end %>
91
+ </tbody>
92
+ </table>
93
+
94
+ <br />
95
+
96
+ <div class="flickr_pagination" style="text-align: left;">
97
+ <%= page_entries_info @klass_data %>
98
+ <br /><br />
99
+ <div id="lower_pagination_overlay" class="pagination_overlay" style="height: 16px;">
100
+ <%= will_paginate @klass_data %>
101
+ </div>
102
+ </div>
103
+ <div style="clear: both;"/>
104
+ <br />
105
+ <% end # @klass_data.count > 0 %>
106
+
107
+ <% @klass_info.global_custom_fields(controller.action_name.to_sym).each do |field| %>
108
+ <%= render field[:partial], {field[:record_data_parameter].to_sym => @klass_data}.merge(field[:additional_partial_parameters]) %><br/>
109
+ <% end %>
110
+
111
+ <div style="clear: both;"/>
112
+ <% if is_allowed_to_update? %>
113
+ <%= link_to "New #{@klass_info[:name]}", new_path(:class_name => @klass_info[:name]) %>
114
+ <% end %>
115
+
116
+ <div style="clear: both;"/>
117
+ <br />
@@ -0,0 +1,17 @@
1
+ <h1><%= "Editing #{@klass_info[:name]}" %></h1>
2
+
3
+ <%= form_for(
4
+ @klass_data,
5
+ :as => @klass_info[:name_as_sym],
6
+ :url => update_path(:class_name => @klass_info[:name], :id => @klass_data.id),
7
+ :html => {:multipart => 'true'},
8
+ :method => :put
9
+ ) do |f| %>
10
+ <%= render 'form', :f => f %>
11
+ <% end %>
12
+
13
+ <% if ::Crud::KlassInfo.primary_key_is_id?(@klass_info[:class]) %>
14
+ <%= link_to 'Show', show_path(:class_name => @klass_info[:name], :id => @klass_data.id) %> |
15
+ <% end %>
16
+
17
+ <%= link_to "Back (List all #{@klass_info[:name].pluralize})", index_path(:class_name => @klass_info[:name]) %>
@@ -0,0 +1,6 @@
1
+ <%= stylesheet_link_tag "crud/pagination", :media => "all" %>
2
+ <%= javascript_include_tag "crud/pagination" %>
3
+ <h1><%= "Listing #{@klass_info[:name].pluralize}" %></h1>
4
+ <div id="klass_data" style="min-width: 1045px;">
5
+ <%= render('klass_data') %>
6
+ </div>
@@ -0,0 +1 @@
1
+ $("#klass_data").html("<%= escape_javascript(render("klass_data")) %>");
@@ -0,0 +1,13 @@
1
+ <h1><%= "New #{@klass_info[:name]}" %></h1>
2
+
3
+ <%= form_for(
4
+ @klass_data,
5
+ :as => @klass_info[:name_as_sym],
6
+ :url => create_path(:class_name => @klass_info[:name]),
7
+ :html => {:multipart => 'true'},
8
+ :method => :post
9
+ ) do |f| %>
10
+ <%= render 'form', :f => f %>
11
+ <% end %>
12
+
13
+ <%= link_to "Back (List all #{@klass_info[:name].pluralize})", index_path(:class_name => @klass_info[:name]) %>
@@ -0,0 +1,69 @@
1
+ <%= render 'error_messages', :model => @klass_data %>
2
+
3
+ <% @visible_attributes.each do |attribute| %>
4
+ <p>
5
+ <b><%= label(@klass_info[:name].to_sym, attribute[:column_name].to_sym) %>:</b>
6
+ <%= render_attribute_value_and_custom_fields(attribute, @klass_data, @klass_info) %>
7
+ </p>
8
+ <% end %>
9
+
10
+ <br/>
11
+
12
+ <% unless @klass_info[:has_one].empty? %>
13
+ <b>Has one:</b><br/>
14
+ <% @klass_info[:has_one].each do |association| %>
15
+ <% association_value = @klass_data.send("#{association[:association_name]}") %>
16
+ <%= "#{association[:association_name]}" %>
17
+ <% if association_value && ::Crud::KlassInfo.primary_key_is_id?(association_value.class) %>
18
+ [<%= link_to("#{association_value}", show_path(:class_name => association_value.class.name, :id => association_value.id)) %>]
19
+ <% end %>
20
+ <br/>
21
+ <% end %>
22
+ <% end %>
23
+
24
+ <% unless @klass_info[:has_many].empty? %>
25
+ <b>Has many:</b><br/>
26
+ <% @klass_info[:has_many].each do |association| %>
27
+ <% association_values = @klass_data.send("#{association[:association_name]}") %>
28
+ <%= "#{association[:association_name]}" %>
29
+ <% if association_values %>
30
+ <% association_values.each do |association_value| %>
31
+ <% if ::Crud::KlassInfo.primary_key_is_id?(association_value.class) %>
32
+ [<%= link_to("#{association_value}", show_path(:class_name => association_value.class.name, :id => association_value.id)) %>]
33
+ <% end %>
34
+ <% end %>
35
+ <% else %>
36
+ <%= "(0)" %>
37
+ <% end %>
38
+ <br/>
39
+ <% end %>
40
+ <% end %>
41
+
42
+ <% unless @klass_info[:has_and_belongs_to_many].empty? %>
43
+ <b>Has and belongs to many:</b><br/>
44
+ <% @klass_info[:has_and_belongs_to_many].each do |association| %>
45
+ <% association_values = @klass_data.send("#{association[:association_name]}") %>
46
+ <%= "#{association[:association_name]}" %>
47
+ <% if association_values %>
48
+ <% association_values.each do |association_value| %>
49
+ <% if ::Crud::KlassInfo.primary_key_is_id?(association_value.class) %>
50
+ [<%= link_to("#{association_value}", show_path(:class_name => association_value.class.name, :id => association_value.id)) %>]
51
+ <% end %>
52
+ <% end %>
53
+ <% else %>
54
+ <%= "(0)" %>
55
+ <% end %>
56
+ <br/>
57
+ <% end %>
58
+ <% end %>
59
+
60
+ <br/>
61
+
62
+ <% @klass_info.global_custom_fields(controller.action_name.to_sym).each do |field| %>
63
+ <%= render field[:partial], {field[:record_data_parameter].to_sym => @klass_data}.merge(field[:additional_partial_parameters]) %><br/>
64
+ <% end %>
65
+
66
+ <% if is_allowed_to_update? %>
67
+ <%= link_to 'Edit', edit_path(:class_name => @klass_info[:name], :id => @klass_data.id) %> |
68
+ <% end %>
69
+ <%= link_to "Back (List all #{@klass_info[:name].pluralize})", index_path(:class_name => @klass_info[:name]) %>
@@ -0,0 +1,15 @@
1
+ <%= stylesheet_link_tag "crud/dashboard", :media => "all" %>
2
+ <%= javascript_include_tag "crud/dashboard" %>
3
+ <h1>CRUD Dashboard</h1>
4
+ <h2>Select the class you wish to manipulate</h2>
5
+ <%= select_tag 'klass_list', options_for_select_tag, :prompt => 'Select a class' %><br/>
6
+ <h2>Model path:</h2>
7
+ <% Crud.model_path.each do |path_element| %>
8
+ <%= "#{path_element}" %><br/>
9
+ <% end %>
10
+ <% if false %>
11
+ <h2>Class list:</h2>
12
+ <% @klass_list.all.each do |klass| %>
13
+ <%= "#{klass.to_s}" %><br/>
14
+ <% end %>
15
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>CRUD</title>
5
+ <%= stylesheet_link_tag "crud/application", :media => "all" %>
6
+ <%= javascript_include_tag "crud/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body class="<%= (@klass_info ? 'crud_' + @klass_info[:name_as_sym].to_s : params[:controller].gsub('/','_')) %>">
10
+ <%= render 'crud/crud/flash_messages' %>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
@@ -0,0 +1,8 @@
1
+ <%
2
+ rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
3
+ rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
4
+ std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
5
+ %>
6
+ default: <%= std_opts %> features
7
+ wip: --tags @wip:3 --wip features
8
+ rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip