erd 0.6.4 → 0.8.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 614e01232d2efeca93c7bed35a751e25a9ee991e2f51e80e171f918fc7f243ef
4
- data.tar.gz: 357077faae8695c34f34fda83f3f4437c95b1725d452c4b262cfbf68648edf28
3
+ metadata.gz: 1e9b918036131dd6376ed19adf3f6533b6caf0987a87f78b04944881ec579695
4
+ data.tar.gz: 591899522e0d2247e5bb999c88c182baeee7a90912f6f8c946bb044e83142a13
5
5
  SHA512:
6
- metadata.gz: 07a9c92343e1d277fbe84f944f08c8d3adb7ae1e166bd04b59606d7325ed25adb2c60f03aee27696e8bda48fc56ba182fde0a31cb0110aa19ad81a41ea608285
7
- data.tar.gz: 15f84992ff7fc3d83cf3df98902afaa22df912ea860345755dd21b06a7521c2d86b2a997d14ebd2cb2d59594ebf211f72271f0375b766c6bc526a58f84518144
6
+ metadata.gz: 36353f77def4b6e65e4e565c87be9a9838dbc11c5e86475aada0435d8062a010c3a683c430bf9b1620289ebddfca5ea871ffbb4f7a4fa384402451489e5590ef
7
+ data.tar.gz: 175f0d4f165dd2fa3148865e4cfc898dbae572da4c200b1b68bb6cbf9450f4b01247ccfe5e189e6e34a8dbba7216d3291285f2464b24a01e67c0fa2b4a20c31b
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # Erd
2
+
3
+ A Rails engine for drawing your app's ER diagram and operating migrations
4
+
5
+
6
+ ## Requirements
7
+
8
+ * Rails 7.0, 6.1, 6.0, 5.2, 5.1, 5.0, 4.2, 4.1, 4.0, 3.2, or 3.1
9
+
10
+ * Graphviz
11
+
12
+
13
+ ## Installation
14
+
15
+ Bundle 'erd' gem to your existing Rails app's Gemfile:
16
+ ```ruby
17
+ gem 'erd', group: :development
18
+
19
+ ```
20
+
21
+
22
+ ## Usage
23
+
24
+ Browse at your http://localhost:3000/erd
25
+
26
+
27
+ ## Features
28
+
29
+ ### Show Mode
30
+
31
+ * Erd draws an ER diagram based on your app's database and models.
32
+
33
+ * You can drag and arrange the positions of each model.
34
+
35
+ * Then you can save the positions to a local file `db/erd_positions.json`, so you can share the diagram between the team members.
36
+
37
+ ### Edit Mode
38
+
39
+ * You can operate DB schema manipulations such as `add column`, `rename column`, `alter column`, `create model (as well as table)`, and `drop table`.
40
+
41
+ * Then, Erd generates migration files on the server.
42
+
43
+ * And you can run each migration on your browser super quickly.
44
+
45
+
46
+ ## TODO
47
+
48
+ * Fix buggy JS
49
+
50
+ * drop column (need to think of the UI)
51
+
52
+ * stop depending on Graphviz
53
+
54
+ * tests
55
+
56
+ * cleaner code (the code is horrible. Please don't read the code, though of course your patches welcome)
57
+
58
+
59
+ ## Contributing to Erd
60
+
61
+ * Send me your pull requests!
62
+
63
+
64
+ ## Team
65
+
66
+ * [Akira Matsuda][https://github.com/amatsuda]
67
+ * [Teppei Machida][http://github.com/machida] (design)
68
+
69
+
70
+ ## Copyright
71
+
72
+ Copyright (c) 2012 Akira Matsuda. See MIT-LICENSE for further details.
@@ -6,62 +6,65 @@ require 'erd/application_controller'
6
6
 
7
7
  module Erd
8
8
  class ErdController < ::Erd::ApplicationController
9
+ POSITIONS_JSON_FILE = Rails.root.join('db/erd_positions.json').freeze
10
+ OLD_POSITIONS_JSON_FILE = Rails.root.join('db/erd_positions.json').freeze # for compatibility
11
+
9
12
  def index
10
- plain = generate_plain
11
- positions = if (json = Rails.root.join('tmp/erd_positions.json')).exist?
12
- ActiveSupport::JSON.decode json.read
13
- else
14
- {}
15
- end
16
- @erd = render_plain plain, positions
13
+ @erd = render_plain generate_plain, saved_positions
14
+ end
17
15
 
16
+ def edit
17
+ @erd = render_plain generate_plain, saved_positions, true
18
18
  @migrations = Erd::Migrator.status
19
19
  end
20
20
 
21
21
  def update
22
+ if params[:position_changes].present?
23
+ position_changes = ActiveSupport::JSON.decode(params[:position_changes])
24
+ positions = saved_positions
25
+ positions.merge! position_changes.transform_keys(&:tableize)
26
+ POSITIONS_JSON_FILE.open('w') {|f| f.write positions.to_json }
27
+ end
28
+
22
29
  changes = params[:changes].present? ? ActiveSupport::JSON.decode(params[:changes]) : []
23
30
  executed_migrations, failed_migrations = [], []
24
31
  changes.each do |row|
25
32
  begin
26
33
  action, model, column, from, to = row['action'], row['model'], row['column'], row['from'], row['to']
27
- if action == 'move'
34
+
35
+ case action
36
+ when 'create_model'
37
+ columns = column.split(' ').compact
38
+ generated_migration_file = Erd::GenaratorRunner.execute_generate_model model, columns
39
+ when 'remove_model'
40
+ model = model.tableize
41
+ generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "drop_#{model}"
42
+ gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n drop_table :#{model}\n end"
43
+ when 'rename_model'
44
+ _model, from, to = from.tableize, to.tableize, model.tableize
45
+ generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "rename_#{from}_to_#{to}"
46
+ gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n rename_table :#{from}, :#{to}\n end"
47
+ when 'add_column'
28
48
  model = model.tableize
29
- json_file = Rails.root.join('tmp', 'erd_positions.json')
30
- positions = json_file.exist? ? ActiveSupport::JSON.decode(json_file.read) : {}
31
- positions[model] = to
32
- json_file.open('w') {|f| f.write positions.to_json}
49
+ name_and_type = column.scan(/(.*)\((.*?)\)/).first
50
+ name, type = name_and_type[0], name_and_type[1]
51
+ generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "add_#{name}_to_#{model}", ["#{name}:#{type}"]
52
+ when 'rename_column'
53
+ model = model.tableize
54
+ generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "rename_#{model}_#{from}_to_#{to}"
55
+ gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n rename_column :#{model}, :#{from}, :#{to}\n end"
56
+ when 'alter_column'
57
+ model = model.tableize
58
+ generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "change_#{model}_#{column}_type_to_#{to}"
59
+ gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n change_column :#{model}, :#{column}, :#{to}\n end"
60
+ when 'move'
61
+ # do nothing
33
62
  else
34
- case action
35
- when 'create_model'
36
- columns = column.split(' ').compact
37
- generated_migration_file = Erd::GenaratorRunner.execute_generate_model model, columns
38
- when 'remove_model'
39
- model = model.tableize
40
- generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "drop_#{model}"
41
- gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n drop_table :#{model}\n end"
42
- when 'rename_model'
43
- _model, from, to = from.tableize, to.tableize, model.tableize
44
- generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "rename_#{from}_to_#{to}"
45
- gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n rename_table :#{from}, :#{to}\n end"
46
- when 'add_column'
47
- model = model.tableize
48
- name_and_type = column.scan(/(.*)\((.*?)\)/).first
49
- name, type = name_and_type[0], name_and_type[1]
50
- generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "add_#{name}_to_#{model}", ["#{name}:#{type}"]
51
- when 'rename_column'
52
- model = model.tableize
53
- generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "rename_#{model}_#{from}_to_#{to}"
54
- gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n rename_column :#{model}, :#{from}, :#{to}\n end"
55
- when 'alter_column'
56
- model = model.tableize
57
- generated_migration_file = Erd::GenaratorRunner.execute_generate_migration "change_#{model}_#{column}_type_to_#{to}"
58
- gsub_file generated_migration_file, /def (up|change).* end/m, "def change\n change_column :#{model}, :#{column}, :#{to}\n end"
59
- else
60
- raise "unexpected action: #{action}"
61
- end
62
- Erd::Migrator.run_migrations :up => generated_migration_file
63
- executed_migrations << generated_migration_file
63
+ raise "unexpected action: #{action}"
64
64
  end
65
+
66
+ Erd::Migrator.run_migrations :up => generated_migration_file
67
+ executed_migrations << generated_migration_file
65
68
  rescue ::Erd::MigrationError => e
66
69
  failed_migrations << e.message
67
70
  end
@@ -77,6 +80,16 @@ module Erd
77
80
 
78
81
  private
79
82
 
83
+ def saved_positions
84
+ if POSITIONS_JSON_FILE.exist?
85
+ ActiveSupport::JSON.decode(POSITIONS_JSON_FILE.read)
86
+ elsif OLD_POSITIONS_JSON_FILE.exist?
87
+ ActiveSupport::JSON.decode(OLD_POSITIONS_JSON_FILE.read)
88
+ else
89
+ {}
90
+ end
91
+ end
92
+
80
93
  def generate_plain
81
94
  if Rails.respond_to?(:autoloaders) && Rails.autoloaders.try(:zeitwerk_enabled?)
82
95
  Zeitwerk::Loader.eager_load_all
@@ -115,20 +128,21 @@ module Erd
115
128
  g.output('plain' => String)
116
129
  end
117
130
 
118
- def render_plain(plain, positions)
131
+ def render_plain(plain, positions, edit_mode = false)
119
132
  _scale, svg_width, svg_height = plain.scan(/\Agraph ([\d\.]+) ([\d\.]+) ([\d\.]+)$/).first
120
133
  # node name x y width height label style shape color fillcolor
121
- max_model_x, max_model_y = 0, 0
122
134
  models = plain.scan(/^node ([^ ]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) ([\d\.]+) ([^ ]+) [^ ]+ [^ ]+ [^ ]+ [^ ]+\n/m).map {|model_name, x, y, width, height, label|
123
135
  columns = label.gsub("\\\n", '').split('|')[1].split('\l').map {|name_and_type| name_and_type.scan(/(.*?)\((.*?)\)/).first }.map {|n, t| {:name => n, :type => t} }
124
136
  custom_x, custom_y = positions[model_name.tableize].try(:split, ',')
125
- h = {:model => model_name, :x => (custom_x || (BigDecimal(x) * 72).round), :y => (custom_y || (BigDecimal(y) * 72).round), :width => (BigDecimal(width) * 72).round, :height => height, :columns => columns}
126
- max_model_x, max_model_y = [h[:x].to_i + h[:width].to_i, max_model_x, 1024].max, [h[:y].to_i + h[:height].to_i, max_model_y, 768].max
127
- h
137
+ {:model => model_name, :x => (custom_x || (BigDecimal(x) * 72).round), :y => (custom_y || (BigDecimal(y) * 72).round), :width => (BigDecimal(width) * 72).round, :height => (BigDecimal(height) * 72).round, :columns => columns}
128
138
  }.compact
139
+ max_model_x = models.map {|m| m[:x].to_f + m[:width].to_f }.max
140
+ erd_width = [[(BigDecimal(svg_width) * 72).round, max_model_x].compact.min + 150, 1024].max
141
+ max_model_y = models.map {|m| m[:y].to_f + m[:height].to_f }.max
142
+ erd_height = [[(BigDecimal(svg_height) * 72).round, max_model_y].compact.min + 150, 768].max
129
143
  # edge tail head n x1 y1 .. xn yn [label xl yl] style color
130
144
  edges = plain.scan(/^edge ([^ ]+)+ ([^ ]+)/).map {|from, to| {:from => from, :to => to}}
131
- render_to_string 'erd/erd/erd', :layout => nil, :locals => {:width => [(BigDecimal(svg_width) * 72).round, max_model_x].max, :height => [(BigDecimal(svg_height) * 72).round, max_model_y].max, :models => models, :edges => edges}
145
+ render_to_string 'erd/erd/erd', :layout => nil, :locals => {:width => erd_width, :height => erd_height, :models => models, :edges => edges, :edit_mode => edit_mode}
132
146
  end
133
147
 
134
148
  def gsub_file(path, flag, *args, &block)
@@ -2,12 +2,16 @@
2
2
  <table>
3
3
  <tr>
4
4
  <td>
5
- <span class="column_name_text"><%= column[:name] %></span>
6
- <form class="rename_column_form"><span><input name="model" type="hidden" value="<%= model[:model] %>" /><input name="column" type="hidden" value="<%= column[:name] %>" /><input name="to" type="text" /><input type="submit" value="Change" /></span><a href="#!" class="cancel">Cancel</a></form>
5
+ <span class="column_name_text<%= "#{' edit' if edit_mode}" %>"><%= column[:name] %></span>
6
+ <% if edit_mode %>
7
+ <form class="rename_column_form"><span><input name="model" type="hidden" value="<%= model[:model] %>" /><input name="column" type="hidden" value="<%= column[:name] %>" /><input name="to" type="text" /><input type="submit" value="Change" /></span><a href="#!" class="cancel">Cancel</a></form>
8
+ <% end %>
7
9
  </td>
8
10
  <td>
9
- <span class="column_type_text <%= column[:type] %>"><%= column[:type] %></span>
10
- <form class="alter_column_form"><span><input name="model" type="hidden" value="<%= model[:model] %>" /><input name="column" type="hidden" value="<%= column[:name] %>" /><input name="type" type="hidden" value="<%= column[:type] %>" /><input name="to" type="text" /><input type="submit" value="Change" /></span><a href="#!" class="cancel">Cancel</a></form>
11
+ <span class="column_type_text <%= column[:type] %><%= "#{' edit' if edit_mode}" %>"><%= column[:type] %></span>
12
+ <% if edit_mode %>
13
+ <form class="alter_column_form"><span><input name="model" type="hidden" value="<%= model[:model] %>" /><input name="column" type="hidden" value="<%= column[:name] %>" /><input name="type" type="hidden" value="<%= column[:type] %>" /><input name="to" type="text" /><input type="submit" value="Change" /></span><a href="#!" class="cancel">Cancel</a></form>
14
+ <% end %>
11
15
  </td>
12
16
  </tr>
13
17
  </table>
@@ -1,28 +1,34 @@
1
1
  <div id="erd-<%= model[:model] %>" class="model" style="top: <%= model[:y] %>px; left: <%= model[:x] %>px;" data-model_name="<%= model[:model] %>">
2
- <a href="#!" class="close"><%= image_tag '/erd/close.png' %></a>
3
- <div class="model_name">
2
+ <% if edit_mode %>
3
+ <a href="#!" class="close"><%= image_tag '/erd/close.png' %></a>
4
+ <% end %>
5
+ <div class="model_name<%= "#{' edit' if edit_mode}" %>">
4
6
  <div class="model_name_text"><%= model[:model] %></div>
5
- <form class="rename_model_form">
6
- <table>
7
- <tr>
8
- <td>
9
- <input name="model" type="hidden" value="<%= model[:model] %>"/>
10
- </td>
11
- <td>
12
- <input name="to" type="text" /><input type="submit" value="Change"/>
13
- </td>
14
- </tr>
15
- </table>
16
- <a href="#!" class="cancel">Cancel</a>
17
- </form>
7
+ <% if edit_mode %>
8
+ <form class="rename_model_form">
9
+ <table>
10
+ <tr>
11
+ <td>
12
+ <input name="model" type="hidden" value="<%= model[:model] %>"/>
13
+ </td>
14
+ <td>
15
+ <input name="to" type="text" /><input type="submit" value="Change"/>
16
+ </td>
17
+ </tr>
18
+ </table>
19
+ <a href="#!" class="cancel">Cancel</a>
20
+ </form>
21
+ <% end %>
18
22
  </div>
19
23
  <div class="columns">
20
24
  <ul>
21
- <%= render :partial => 'erd/erd/column', :collection => model[:columns], :locals => {:model => model} -%>
25
+ <%= render :partial => 'erd/erd/column', :collection => model[:columns], :locals => {:model => model, :edit_mode => edit_mode} -%>
22
26
  </ul>
23
27
  </div>
24
28
  <div class="add_column_box">
25
- <a href="#!" class="add_column">add column</a>
29
+ <% if edit_mode %>
30
+ <a href="#!" class="add_column">add column</a>
31
+ <% end %>
26
32
  <form class="add_column_form">
27
33
  <input name="model" type="hidden" value="<%= model[:model] %>" />
28
34
  <table>
@@ -0,0 +1,87 @@
1
+ <div id="erd_box">
2
+ <div id="erd_container">
3
+ <%=raw @erd %>
4
+ </div>
5
+ <div id="open_migration"><%= image_tag '/erd/angle-left.png' %></div>
6
+ <div id="migration">
7
+ <div id="close_migration"><%= image_tag '/erd/angle-right.png' %></div>
8
+ <%- if flash[:executed_migrations].present? -%>
9
+ <div id="executed">
10
+ <h2>Successfully executed following <%= flash[:executed_migrations].values.flatten.count %> migrations!</h2>
11
+ <%- [:up, :down].each do |direction| -%>
12
+ <%- if flash[:executed_migrations][direction].present? -%>
13
+ <h3><%= direction %></h3>
14
+ <ul>
15
+ <%- flash[:executed_migrations][direction].each do |m| -%>
16
+ <li><%= File.basename m.to_s %></li>
17
+ <%- end -%>
18
+ </ul>
19
+ <%- end -%>
20
+ <%- end -%>
21
+ </div>
22
+ <%- end -%>
23
+ <%- if flash[:failed_migrations].present? -%>
24
+ <div id="failed">
25
+ <h2>failed migrations</h2>
26
+ <ul>
27
+ <%- flash[:failed_migrations].each do |m| -%>
28
+ <li><%= m %></li>
29
+ <%- end -%>
30
+ </ul>
31
+ </div>
32
+ <%- end -%>
33
+ <table id="changes">
34
+ <caption>schema changes</caption>
35
+ <thead><tr><th>action</th><th>model</th><th>column</th><th>from</th><th>to</th></tr></thead>
36
+ <tbody></tbody>
37
+ </table>
38
+ <%= form_tag '/erd', :method => :put, :id => 'changes_form' do %>
39
+ <%= hidden_field_tag 'changes' %>
40
+ <%= hidden_field_tag 'position_changes' %>
41
+ <%= submit_tag 'save changes' %>
42
+ <% end %>
43
+ <%= form_tag '/erd/migrate', :method => :put, :id => 'migrate_form' do %>
44
+ <ul id="open_buttons">
45
+ <li><button id="open_up" type="button">up</button></li>
46
+ <li><button id="open_down" type="button">down</button></li>
47
+ <li><button id="close_all" type="button">close</button></li>
48
+ </ul>
49
+ <table id="migration_status">
50
+ <caption>migration status</caption>
51
+ <thead>
52
+ <tr><th class="status">status</th><th class="version">version</th><th class="name">name</th></tr>
53
+ <tr><td colspan="3" class="migrations">
54
+ <button>UNFOLD ALL</button>
55
+ <%= @migrations.count %> migrations in total (up: <%= @migrations.count {|m| m[:status] == 'up'} %>, down: <%= @migrations.count {|m| m[:status] == 'down'} %>)
56
+ </td></tr>
57
+ </thead>
58
+ <tbody>
59
+ <%- @migrations.each do |m| -%>
60
+ <tr class="<%= m[:status] %>">
61
+ <td><label><%= check_box_tag (m[:status] == 'up' ? 'down[]' : 'up[]'), m[:filename], false, :id => "check_#{m[:filename]}" %><%= m[:status] %></label></td>
62
+ <td><%= m[:version] %></td>
63
+ <td class="migration_file_name"><%= m[:name] %></td>
64
+ </tr>
65
+ <%- end -%>
66
+ </tbody>
67
+ </table>
68
+ <%= submit_tag 'run migrations' %>
69
+ <% end %>
70
+ </div>
71
+ <a href="#" id='open_create_model_dialog'%>Create Model</a>
72
+ <div id="create_model_form">
73
+ <form>
74
+ Model Name: <input id="new_model_name" name="new_model_name" type="text" /><br>
75
+ <table id="create_model_table">
76
+ <tbody>
77
+ <tr>
78
+ <td><input name="new_model_column_name_1" type="text" /></td>
79
+ <td class="separator">:</td>
80
+ <td><input name="new_model_column_type_1" type="text" value="string" /></td>
81
+ </tr>
82
+ </tbody>
83
+ </table>
84
+ <div><a href="#" id="new_model_add_column" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"><span class="ui-button-text">Add More Column</span></a></div>
85
+ </form>
86
+ </div>
87
+ </div>
@@ -1,4 +1,4 @@
1
1
  <div id="erd" data-svg_width="<%= width %>" data-svg_height="<%= height %>">
2
- <%= render :partial => 'erd/erd/model', :collection => models -%>
2
+ <%= render :partial => 'erd/erd/model', :collection => models, :locals => {:edit_mode => edit_mode} -%>
3
3
  <script>window.raw_edges = <%= edges.to_json.html_safe %>;</script>
4
4
  </div>
@@ -2,85 +2,16 @@
2
2
  <div id="erd_container">
3
3
  <%=raw @erd %>
4
4
  </div>
5
- <div id="open_migration"><%= image_tag '/erd/angle-left.png' %></div>
6
- <div id="migration">
7
- <div id="close_migration"><%= image_tag '/erd/angle-right.png' %></div>
8
- <%- if flash[:executed_migrations].present? -%>
9
- <div id="executed">
10
- <h2>Successfully executed following <%= flash[:executed_migrations].values.flatten.count %> migrations!</h2>
11
- <%- [:up, :down].each do |direction| -%>
12
- <%- if flash[:executed_migrations][direction].present? -%>
13
- <h3><%= direction %></h3>
14
- <ul>
15
- <%- flash[:executed_migrations][direction].each do |m| -%>
16
- <li><%= File.basename m.to_s %></li>
17
- <%- end -%>
18
- </ul>
19
- <%- end -%>
20
- <%- end -%>
21
- </div>
22
- <%- end -%>
23
- <%- if flash[:failed_migrations].present? -%>
24
- <div id="failed">
25
- <h2>failed migrations</h2>
26
- <ul>
27
- <%- flash[:failed_migrations].each do |m| -%>
28
- <li><%= m %></li>
29
- <%- end -%>
30
- </ul>
31
- </div>
32
- <%- end -%>
33
- <table id="changes">
34
- <caption>schema changes</caption>
35
- <thead><tr><th>action</th><th>model</th><th>column</th><th>from</th><th>to</th></tr></thead>
36
- <tbody></tbody>
37
- </table>
38
- <%= form_tag '/erd', :method => :put, :id => 'changes_form' do %>
39
- <%= hidden_field_tag 'changes' %>
40
- <%= submit_tag 'save changes' %>
41
- <% end %>
42
- <%= form_tag '/erd/migrate', :method => :put, :id => 'migrate_form' do %>
43
- <ul id="open_buttons">
44
- <li><button id="open_up" type="button">up</button></li>
45
- <li><button id="open_down" type="button">down</button></li>
46
- <li><button id="close_all" type="button">close</button></li>
47
- </ul>
48
- <table id="migration_status">
49
- <caption>migration status</caption>
50
- <thead>
51
- <tr><th class="status">status</th><th class="version">version</th><th class="name">name</th></tr>
52
- <tr><td colspan="3" class="migrations">
53
- <button>UNFOLD ALL</button>
54
- <%= @migrations.count %> migrations in total (up: <%= @migrations.count {|m| m[:status] == 'up'} %>, down: <%= @migrations.count {|m| m[:status] == 'down'} %>)
55
- </td></tr>
56
- </thead>
57
- <tbody>
58
- <%- @migrations.each do |m| -%>
59
- <tr class="<%= m[:status] %>">
60
- <td><label><%= check_box_tag (m[:status] == 'up' ? 'down[]' : 'up[]'), m[:filename] %><%= m[:status] %></label></td>
61
- <td><%= m[:version] %></td>
62
- <td class="migration_file_name"><%= m[:name] %></td>
63
- </tr>
64
- <%- end -%>
65
- </tbody>
66
- </table>
67
- <%= submit_tag 'run migrations' %>
68
- <% end %>
69
- </div>
70
- <a href="#" id='open_create_model_dialog'%>Create Model</a>
71
- <div id="create_model_form">
72
- <form>
73
- Model Name: <input id="new_model_name" name="new_model_name" type="text" /><br>
74
- <table id="create_model_table">
75
- <tbody>
76
- <tr>
77
- <td><input name="new_model_column_name_1" type="text" /></td>
78
- <td class="separator">:</td>
79
- <td><input name="new_model_column_type_1" type="text" value="string" /></td>
80
- </tr>
81
- </tbody>
82
- </table>
83
- <div><a href="#" id="new_model_add_column" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"><span class="ui-button-text">Add More Column</span></a></div>
84
- </form>
85
- </div>
5
+ <%= form_tag '/erd', :method => :put, :id => 'changes_form' do %>
6
+ <%= hidden_field_tag 'position_changes' %>
7
+ <% end %>
8
+ <input id="drawer_switch" type="checkbox">
9
+ <label id="drawer_hide_label" class="drawer_switch_label" for="drawer_switch">&gt;&nbsp;&nbsp;Hide Buttons</label>
10
+ <label id="drawer_show_label" class="drawer_switch_label" for="drawer_switch">&lt;</label>
11
+ <nav id="buttons">
12
+ <ul>
13
+ <li><a href="#!" id="save_position_changes" class="menu_button">Save Position Changes</a></li>
14
+ <li><%= link_to 'Edit the Database', :edit, :id => 'link_to_edit', :class => 'menu_button' %></li>
15
+ </ul>
16
+ </nav>
86
17
  </div>
@@ -2,7 +2,7 @@
2
2
  <html>
3
3
  <head>
4
4
  <meta charset='utf-8'>
5
- <title>ERD - <%= Rails.application.class.parent.name %></title>
5
+ <title>ERD - <%= Rails.application.class.name[/[^:]+/] %></title>
6
6
  <%= stylesheet_link_tag '/erd/erd', :media => 'all' %>
7
7
  <%= stylesheet_link_tag 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css', :media => 'all' %>
8
8
  <%= javascript_include_tag 'https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js' %>
data/config/routes.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  Erd::Engine.routes.draw do
4
4
  get '/' => 'erd#index'
5
+ get 'edit' => 'erd#edit'
5
6
  put '/' => 'erd#update'
6
7
  put '/migrate' => 'erd#migrate', :as => 'migrate'
7
8
  root :to => 'erd#index'
data/erd.gemspec CHANGED
@@ -11,9 +11,9 @@ Gem::Specification.new do |gem|
11
11
  gem.homepage = 'https://github.com/amatsuda/erd'
12
12
  gem.license = 'MIT'
13
13
 
14
- gem.files = `git ls-files`.split($\)
15
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.files = Dir.chdir(File.expand_path(__dir__)) do
15
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
16
+ end
17
17
  gem.name = 'erd'
18
18
  gem.require_paths = ['lib']
19
19
  gem.version = Erd::VERSION
data/lib/erd/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Erd
4
- VERSION = '0.6.4'
4
+ VERSION = '0.8.1'
5
5
  end
data/public/erd/erd.css CHANGED
@@ -219,8 +219,9 @@ li {
219
219
  box-shadow: rgba(0, 0, 0, 0.7) 0 2px 2px; }
220
220
  #erd .model .model_name {
221
221
  border-bottom: 1px #444444 solid;
222
- cursor: pointer;
223
222
  margin: 1px 5px 0 5px auto; }
223
+ #erd .model .model_name.edit {
224
+ cursor: pointer; }
224
225
  #erd .model .model_name .model_name_text {
225
226
  text-align: center;
226
227
  display: block;
@@ -229,10 +230,10 @@ li {
229
230
  background: -ms-linear-gradient(top, #eeeeee 0%, #d0d0d0 88%);
230
231
  background: -o-linear-gradient(top, #eeeeee 0%, #d0d0d0 88%);
231
232
  background: linear-gradient(top, #eeeeee 0%, #d0d0d0 88%);
232
- font-size: 13px;
233
+ font-size: 15px;
233
234
  font-weight: bold;
234
235
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);
235
- line-height: 2.2;
236
+ line-height: 1.6;
236
237
  padding: 0 0.8em; }
237
238
  #erd .model .model_name .model_name_text.unsaved {
238
239
  background: #fffebe;
@@ -314,7 +315,7 @@ li {
314
315
  font-size: small;
315
316
  display: block;
316
317
  padding: 0 5px;
317
- line-height: 2;
318
+ line-height: 1.6;
318
319
  background: #444444;
319
320
  color: white;
320
321
  text-decoration: none; }
@@ -328,9 +329,9 @@ li {
328
329
 
329
330
  .columns .column {
330
331
  border-bottom: dotted 1px #cccccc;
331
- padding: 0 0.8em;
332
+ padding: 0 0.5em;
332
333
  clear: both;
333
- line-height: 28px;
334
+ line-height: 20px;
334
335
  font-size: 14px; }
335
336
  .columns .column table {
336
337
  width: 100%; }
@@ -338,12 +339,12 @@ li {
338
339
  background: #f9f9f9; }
339
340
  .columns .column:last-child {
340
341
  border-bottom: none; }
341
- .columns .column .column_name_text,
342
- .columns .column .column_type_text {
342
+ .columns .column .column_name_text.edit,
343
+ .columns .column .column_type_text.edit {
343
344
  cursor: pointer; }
344
345
  .columns .column .column_name_text {
345
346
  margin: 0 1.4em 0 0; }
346
- .columns .column .column_name_text:hover {
347
+ .columns .column .column_name_text.edit:hover {
347
348
  text-decoration: underline; }
348
349
  .columns .column.unsaved {
349
350
  background: #fffebe;
@@ -377,11 +378,11 @@ li {
377
378
  .columns .column .rename_column_form {
378
379
  padding: 8px; }
379
380
  .columns .column .column_type_text {
380
- font-size: 10px;
381
+ font-size: 13px;
381
382
  float: right;
382
383
  display: block;
383
384
  line-height: 16px;
384
- margin: 5px 0 0;
385
+ margin: 1px 0 0;
385
386
  -webkit-border-radius: 4px;
386
387
  -moz-border-radius: 4px;
387
388
  -ms-border-radius: 4px;
@@ -395,7 +396,7 @@ li {
395
396
  background: #f9eee9;
396
397
  color: #444444;
397
398
  border-style: solid; }
398
- .columns .column .column_type_text:hover {
399
+ .columns .column .column_type_text.edit:hover {
399
400
  border-color: #e36c33;
400
401
  background: #edd0c2; }
401
402
  .columns .column .column_type_text.date, .columns .column .column_type_text.time, .columns .column .column_type_text.timestamp, .columns .column .column_type_text.datetime {
@@ -403,7 +404,7 @@ li {
403
404
  background: #f3e2e4;
404
405
  color: #444444;
405
406
  border-style: solid; }
406
- .columns .column .column_type_text.date:hover, .columns .column .column_type_text.time:hover, .columns .column .column_type_text.timestamp:hover, .columns .column .column_type_text.datetime:hover {
407
+ .columns .column .column_type_text.edit.date:hover, .columns .column .column_type_text.edit.time:hover, .columns .column .column_type_text.edit.timestamp:hover, .columns .column .column_type_text.edit.datetime:hover {
407
408
  border-color: #d0394d;
408
409
  background: #e4bec3; }
409
410
  .columns .column .column_type_text.boolean {
@@ -411,7 +412,7 @@ li {
411
412
  background: #c7dce6;
412
413
  color: #444444;
413
414
  border-style: solid; }
414
- .columns .column .column_type_text.boolean:hover {
415
+ .columns .column .column_type_text.edit.boolean:hover {
415
416
  border-color: #2e87b3;
416
417
  background: #a3c6d7; }
417
418
  .columns .column .column_type_text.text {
@@ -419,7 +420,7 @@ li {
419
420
  background: #efe7d3;
420
421
  color: #444444;
421
422
  border-style: solid; }
422
- .columns .column .column_type_text.text:hover {
423
+ .columns .column .column_type_text.edit.text:hover {
423
424
  border-color: #cb9d2b;
424
425
  background: #e1d2ae; }
425
426
  .columns .column .column_type_text.decimal {
@@ -427,7 +428,7 @@ li {
427
428
  background: #dfdf50;
428
429
  color: #444444;
429
430
  border-style: solid; }
430
- .columns .column .column_type_text.decimal:hover {
431
+ .columns .column .column_type_text.edit.decimal:hover {
431
432
  border-color: #5e5e05;
432
433
  background: #d5d527; }
433
434
  .columns .column .column_type_text.float {
@@ -435,7 +436,7 @@ li {
435
436
  background: silver;
436
437
  color: #444444;
437
438
  border-style: solid; }
438
- .columns .column .column_type_text.float:hover {
439
+ .columns .column .column_type_text.edit.float:hover {
439
440
  border-color: #684b53;
440
441
  background: #a6a6a6; }
441
442
  .columns .column .column_type_text.integer {
@@ -443,7 +444,7 @@ li {
443
444
  background: #dfdfe0;
444
445
  color: #444444;
445
446
  border-style: solid; }
446
- .columns .column .column_type_text.integer:hover {
447
+ .columns .column .column_type_text.edit.integer:hover {
447
448
  border-color: #606493;
448
449
  background: #c5c5c7; }
449
450
  .columns .column .column_type_text.primary_key {
@@ -451,7 +452,7 @@ li {
451
452
  background: #f9efe7;
452
453
  color: #444444;
453
454
  border-style: solid; }
454
- .columns .column .column_type_text.primary_key:hover {
455
+ .columns .column .column_type_text.edit.primary_key:hover {
455
456
  border-color: #e47e30;
456
457
  background: #eed3bf; }
457
458
  .columns .column .column_type_text.string {
@@ -459,7 +460,7 @@ li {
459
460
  background: #d3e09e;
460
461
  color: #444444;
461
462
  border-style: solid; }
462
- .columns .column .column_type_text.string:hover {
463
+ .columns .column .column_type_text.edit.string:hover {
463
464
  border-color: #7f9919;
464
465
  background: #c1d477; }
465
466
  .columns .column .column_type_text.unsaved {
@@ -510,6 +511,54 @@ li {
510
511
  #model_name_changes, #column_name_changes {
511
512
  display: none; }
512
513
 
514
+ #drawer_switch {
515
+ display: none; }
516
+ #drawer_switch:checked ~ #buttons {
517
+ right: -400px; }
518
+ #drawer_switch:checked ~ #drawer_hide_label {
519
+ visibility: hidden; }
520
+ #drawer_switch:checked ~ #drawer_show_label {
521
+ visibility: visible; }
522
+
523
+ #buttons {
524
+ position: fixed;
525
+ top: 70px;
526
+ right: 15px;
527
+ -webkit-transition: all 0.5s;
528
+ transition: all 0.5s; }
529
+
530
+ .drawer_switch_label {
531
+ position: fixed;
532
+ right: 15px;
533
+ top: 10px;
534
+ background: rgba(0, 0, 0, 0.6);
535
+ padding: 12px 20px;
536
+ color: white;
537
+ cursor: pointer;
538
+ text-decoration: none;
539
+ font-size: 13px; }
540
+ .drawer_switch_label:hover {
541
+ background: rgba(0, 0, 0, 0.8); }
542
+ #drawer_show_label {
543
+ visibility: hidden; }
544
+
545
+ .menu_button {
546
+ position: relative;
547
+ right: 0;
548
+ background: rgba(0, 0, 0, 0.6);
549
+ padding: 12px 20px;
550
+ color: white;
551
+ text-decoration: none;
552
+ font-size: 13px; }
553
+ .menu_button:hover {
554
+ background: rgba(0, 0, 0, 0.8); }
555
+ #save_position_changes {
556
+ visibility: hidden;
557
+ top: 70px;
558
+ background: rgba(191, 0, 0, 0.6); }
559
+ #save_position_changes:hover {
560
+ background: rgba(191, 0, 0, 0.8); }
561
+
513
562
  #open_create_model_dialog {
514
563
  position: fixed;
515
564
  right: 15px;
data/public/erd/erd.js CHANGED
@@ -19,10 +19,12 @@ class ERD {
19
19
  this.handle_new_model_add_column_click = this.handle_new_model_add_column_click.bind(this);
20
20
  this.handle_open_migration_click = this.handle_open_migration_click.bind(this);
21
21
  this.handle_close_migration_click = this.handle_close_migration_click.bind(this);
22
+ this.handle_save_position_changes_click = this.handle_save_position_changes_click.bind(this);
22
23
  this.name = name;
23
24
  this.elem = elem;
24
25
  this.edges = edges;
25
26
  this.paper = Raphael(this.name, this.elem.data('svg_width'), this.elem.data('svg_height'));
27
+ this.position_changes = {};
26
28
  this.setup_handlers();
27
29
  const models = this.elem.find('.model');
28
30
  this.models = {};
@@ -122,11 +124,13 @@ class ERD {
122
124
  const from = target.data('original_position');
123
125
  const to = [target.css('left').replace(/px$/, ''), target.css('top').replace(/px$/, '')].join();
124
126
  this.upsert_change('move', model_name, '', '', to);
127
+ this.position_changes[model_name] = to;
125
128
  this.connect_arrows(this.edges.filter(e=> (e.from === model_name) || (e.to === model_name)));
129
+ document.getElementById("save_position_changes").style.visibility = "visible";
126
130
  }
127
131
 
128
132
  setup_click_handlers() {
129
- $('div.model_name_text, span.column_name_text, span.column_type_text').on('click', this.handle_text_elem_click);
133
+ $('div.model_name_text.edit, span.column_name_text.edit, span.column_type_text.edit').on('click', this.handle_text_elem_click);
130
134
  $('div.model a.add_column').on('click', this.handle_add_column_click);
131
135
  $('div.model a.cancel').on('click', this.handle_cancel_click);
132
136
  $('div.model a.close').on('click', this.handle_remove_model_click);
@@ -134,6 +138,7 @@ class ERD {
134
138
  $('div.model a.cancel').on('click', this.handle_cancel_click);
135
139
  $('div#open_migration').on('click', this.handle_open_migration_click);
136
140
  $('div#close_migration').on('click', this.handle_close_migration_click);
141
+ $('#save_position_changes').on('click', this.handle_save_position_changes_click);
137
142
  }
138
143
 
139
144
  setup_submit_handlers() {
@@ -165,6 +170,7 @@ class ERD {
165
170
  return change;
166
171
  }).toArray();
167
172
  $('#changes_form').find('input[name=changes]').val(JSON.stringify(changes));
173
+ $('#changes_form').find('input[name=position_changes]').val(JSON.stringify(this.position_changes));
168
174
  }
169
175
 
170
176
  handle_add_column(ev) {
@@ -359,6 +365,11 @@ class ERD {
359
365
  .parent().hide()
360
366
  .prev('div').show();
361
367
  }
368
+
369
+ handle_save_position_changes_click(ev) {
370
+ $('#changes_form').find('input[name=position_changes]').val(JSON.stringify(this.position_changes));
371
+ $('#changes_form').submit();
372
+ }
362
373
  }
363
374
 
364
375
  $(function() {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Akira Matsuda
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-25 00:00:00.000000000 Z
11
+ date: 2022-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-graphviz
@@ -161,12 +161,13 @@ files:
161
161
  - ".travis.yml"
162
162
  - Gemfile
163
163
  - MIT-LICENSE
164
- - README.rdoc
164
+ - README.md
165
165
  - Rakefile
166
166
  - app/controllers/erd/application_controller.rb
167
167
  - app/controllers/erd/erd_controller.rb
168
168
  - app/views/erd/erd/_column.html.erb
169
169
  - app/views/erd/erd/_model.html.erb
170
+ - app/views/erd/erd/edit.html.erb
170
171
  - app/views/erd/erd/erd.html.erb
171
172
  - app/views/erd/erd/index.html.erb
172
173
  - app/views/layouts/erd/application.html.erb
@@ -196,21 +197,11 @@ files:
196
197
  - public/erd/erd.css
197
198
  - public/erd/erd.js
198
199
  - src/assets/stylesheets/erd/erd.css.scss
199
- - test/fake_app/config/database.yml
200
- - test/fake_app/db/migrate/20120428022519_create_authors.rb
201
- - test/fake_app/db/migrate/20120428022535_create_books.rb
202
- - test/fake_app/db/schema.rb
203
- - test/fake_app/fake_app.rb
204
- - test/fake_app/log/.gitignore
205
- - test/fake_app/tmp/.gitkeep
206
- - test/features/erd_test.rb
207
- - test/lib/migrator_test.rb
208
- - test/test_helper.rb
209
200
  homepage: https://github.com/amatsuda/erd
210
201
  licenses:
211
202
  - MIT
212
203
  metadata: {}
213
- post_install_message:
204
+ post_install_message:
214
205
  rdoc_options: []
215
206
  require_paths:
216
207
  - lib
@@ -225,18 +216,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
216
  - !ruby/object:Gem::Version
226
217
  version: '0'
227
218
  requirements: []
228
- rubygems_version: 3.0.3
229
- signing_key:
219
+ rubygems_version: 3.4.0.dev
220
+ signing_key:
230
221
  specification_version: 4
231
222
  summary: erd engine on Rails
232
- test_files:
233
- - test/fake_app/config/database.yml
234
- - test/fake_app/db/migrate/20120428022519_create_authors.rb
235
- - test/fake_app/db/migrate/20120428022535_create_books.rb
236
- - test/fake_app/db/schema.rb
237
- - test/fake_app/fake_app.rb
238
- - test/fake_app/log/.gitignore
239
- - test/fake_app/tmp/.gitkeep
240
- - test/features/erd_test.rb
241
- - test/lib/migrator_test.rb
242
- - test/test_helper.rb
223
+ test_files: []
data/README.rdoc DELETED
@@ -1,66 +0,0 @@
1
- = Erd
2
-
3
- A Rails engine for drawing your app's ER diagram and operating migrations
4
-
5
-
6
- == Requirements
7
-
8
- * Rails 5.2, 5.1, 5.0, 4.2, 4.1, 4.0, 3.2, or 3.1
9
-
10
- * Graphviz
11
-
12
-
13
- == Installation
14
-
15
- Add 'erd' gem to your existing app's Gemfile:
16
- gem 'erd'
17
-
18
- Bundle it:
19
- % bundle
20
-
21
-
22
- == Usage
23
-
24
- Browse at your http://localhost:3000/erd
25
-
26
-
27
- == Features
28
-
29
- * Erd draws an ER diagram based on your app's database and models
30
-
31
- * You can drag and arrange the positions of each model
32
-
33
- * You can operate DB schema manipulations such as `add column`, `rename column`, `alter column`, `create model (as well as table)`, and `drop table`
34
-
35
- * Then, Erd generates migration files on the server
36
-
37
- * And you can run each migration on your browser
38
-
39
-
40
- == TODO
41
-
42
- * Fix buggy JS
43
-
44
- * drop column (need to think of the UI)
45
-
46
- * stop depending on Graphviz
47
-
48
- * tests
49
-
50
- * cleaner code (the code is horrible. Please don't read the code, though of course your patches welcome)
51
-
52
-
53
- == Contributing to Erd
54
-
55
- * Send me your pull requests!
56
-
57
-
58
- == Team
59
-
60
- * {Akira Matsuda}[https://github.com/amatsuda]
61
- * {Teppei Machida}[http://github.com/machida] (design)
62
-
63
-
64
- == Copyright
65
-
66
- Copyright (c) 2012 Akira Matsuda. See MIT-LICENSE for further details.
@@ -1,3 +0,0 @@
1
- development:
2
- adapter: sqlite3
3
- database: ":memory:"
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateAuthors < ActiveRecord::VERSION::MAJOR >= 5 ? ActiveRecord::Migration[5.0] : ActiveRecord::Migration
4
- def change
5
- create_table :authors do |t|
6
- t.string :name
7
-
8
- t.timestamps
9
- end
10
- end
11
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateBooks < ActiveRecord::VERSION::MAJOR >= 5 ? ActiveRecord::Migration[5.0] : ActiveRecord::Migration
4
- def change
5
- create_table :books do |t|
6
- t.references :author
7
- t.string :title
8
-
9
- t.timestamps
10
- end
11
- end
12
- end
File without changes
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_record'
4
- require 'action_controller/railtie'
5
-
6
- # config
7
- module ErdApp
8
- class Application < Rails::Application
9
- # Rais.root
10
- config.root = File.dirname(__FILE__)
11
-
12
- config.secret_token = 'fall to your knees and repent if you please'
13
- config.session_store :cookie_store, :key => '_myapp_session'
14
- config.active_support.deprecation = :log
15
- config.eager_load = false
16
-
17
- config.app_generators.orm :active_record, :migration => true, :timestamps => true
18
- end
19
- end
20
- ErdApp::Application.initialize!
21
- ErdApp::Application.routes.draw {}
22
-
23
- # models
24
- class Author < ActiveRecord::Base
25
- has_many :books
26
- end
27
- class Book < ActiveRecord::Base
28
- belongs_to :author
29
- end
30
-
31
- # helpers
32
- module ApplicationHelper; end
@@ -1 +0,0 @@
1
- *.log
File without changes
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class ErdIndexTest < ActionDispatch::IntegrationTest
6
- test 'with author and book model' do
7
- visit '/erd'
8
-
9
- if Capybara::VERSION > '3'
10
- assert has_content? 'Author', :minimum => 1
11
- else
12
- assert has_content? 'Author'
13
- end
14
- assert has_content? 'name'
15
- assert has_content? 'Book'
16
- assert has_content? 'title'
17
- end
18
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class MigratorTest < ActiveSupport::TestCase
6
- teardown do
7
- Dir.glob(Rails.root.join('db/migrate/*.rb')).each do |f|
8
- FileUtils.rm f unless File.basename(f).in? %w(20120428022519_create_authors.rb 20120428022535_create_books.rb)
9
- end
10
- end
11
-
12
- sub_test_case '.status' do
13
- test 'when all migrations are up' do
14
- assert_equal [{:status => 'up', :version => '20120428022519', :name => 'create_authors', :filename => '20120428022519_create_authors.rb'}, {:status => 'up', :version => '20120428022535', :name => 'create_books', :filename => '20120428022535_create_books.rb'}], Erd::Migrator.status
15
- end
16
-
17
- test 'when one is undone' do
18
- FileUtils.touch Rails.root.join('db/migrate/20999999999999_create_foobars.rb')
19
-
20
- assert_equal [{:status => 'up', :version => '20120428022519', :name => 'create_authors', :filename => '20120428022519_create_authors.rb'}, {:status => 'up', :version => '20120428022535', :name => 'create_books', :filename => '20120428022535_create_books.rb'}, {:status => 'down', :version => '20999999999999', :name => 'create_foobars', :filename => '20999999999999_create_foobars.rb'}], Erd::Migrator.status
21
- end
22
- end
23
-
24
- sub_test_case '.run_migrations' do
25
- setup do
26
- File.open(Rails.root.join('db/migrate/20999999999999_create_foobars.rb'), 'w') do |f|
27
- f.puts 'class CreateFoobars < ActiveRecord::VERSION::MAJOR >= 5 ? ActiveRecord::Migration[5.0] : ActiveRecord::Migration; end'
28
- end
29
-
30
- if defined? ActiveRecord::MigrationContext # >= 5.2
31
- mock.instance_of(ActiveRecord::MigrationContext).run(:up, 20999999999999)
32
- else
33
- mock(ActiveRecord::Migrator).run(:up, ['db/migrate'], 20999999999999)
34
- end
35
- mock(ActiveRecord::SchemaDumper).dump(ActiveRecord::Base.connection, anything)
36
- end
37
- test 'runs migration by version number' do
38
- Erd::Migrator.run_migrations(:up => ['20999999999999'])
39
- end
40
- test 'runs migration by migration filename' do
41
- Erd::Migrator.run_migrations(:up => [Rails.root.join('db/migrate/20999999999999_create_foobars.rb')])
42
- end
43
- end
44
- end
45
-
46
- class GenaratorRunnerTest < ActiveSupport::TestCase
47
- setup do
48
- stub.proxy(Time).now {|t| stub(t).utc { Time.parse '2012/5/12 13:26' } }
49
- end
50
- teardown do
51
- Dir.glob(Rails.root.join('db/migrate/*.rb')).each do |f|
52
- FileUtils.rm f unless File.basename(f).in? %w(20120428022519_create_authors.rb 20120428022535_create_books.rb)
53
- end
54
- end
55
-
56
- test '.execute_generate_migration' do
57
- assert_includes Erd::GenaratorRunner.execute_generate_migration('create_foobars'), 'db/migrate/20120512132600_create_foobars.rb'
58
- end
59
- end
data/test/test_helper.rb DELETED
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
- $LOAD_PATH.unshift(File.dirname(__FILE__))
5
-
6
- ENV['RAILS_ENV'] = 'development'
7
-
8
- # load Rails first
9
- require 'rails'
10
- require 'action_controller/railtie'
11
- require 'active_record/railtie'
12
- require 'erd'
13
- require 'fake_app/fake_app'
14
- require 'test/unit/rails/test_help'
15
- Bundler.require
16
- require 'capybara'
17
- require 'selenium/webdriver'
18
-
19
- begin
20
- require "action_dispatch/system_test_case"
21
- rescue LoadError
22
- Capybara.register_driver :chrome do |app|
23
- options = Selenium::WebDriver::Chrome::Options.new(:args => %w[no-sandbox headless disable-gpu])
24
- Capybara::Selenium::Driver.new(app, :browser => :chrome, :options => options)
25
- end
26
- Capybara.javascript_driver = :chrome
27
- else
28
- ActionDispatch::SystemTestCase.driven_by(:selenium, :using => :headless_chrome)
29
- end
30
-
31
- ActiveRecord::Migration.verbose = false
32
- if defined? ActiveRecord::MigrationContext # >= 5.2
33
- ActiveRecord::Migrator.migrations_paths = Rails.application.paths['db/migrate'].to_a
34
- ActiveRecord::Base.connection.migration_context.migrate
35
- else
36
- ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths.map {|p| Rails.root.join p}, nil)
37
- end