neo4j-meta_model 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/javascripts/admin/models.js.coffee +25 -0
  6. data/app/assets/javascripts/meta_model.js.coffee +217 -0
  7. data/app/assets/javascripts/router.js.coffee +5 -0
  8. data/app/assets/javascripts/store.js.coffee +12 -0
  9. data/app/assets/javascripts/templates/application.emblem +3 -0
  10. data/app/assets/javascripts/templates/components/model-list-item.emblem +6 -0
  11. data/app/assets/javascripts/templates/components/model-list.emblem +4 -0
  12. data/app/assets/javascripts/templates/has_associations/index.emblem +25 -0
  13. data/app/assets/javascripts/templates/has_associations/new.emblem +50 -0
  14. data/app/assets/javascripts/templates/index.emblem +6 -0
  15. data/app/assets/javascripts/templates/models/edit.emblem +40 -0
  16. data/app/assets/javascripts/templates/models/hierarchy.emblem +8 -0
  17. data/app/assets/stylesheets/meta_model.css.scss +113 -0
  18. data/app/controllers/meta_model/application_controller.rb +12 -0
  19. data/app/controllers/meta_model/meta/has_associations_controller.rb +44 -0
  20. data/app/controllers/meta_model/meta/models_controller.rb +80 -0
  21. data/app/controllers/meta_model/meta/properties_controller.rb +36 -0
  22. data/app/controllers/meta_model/meta_controller.rb +7 -0
  23. data/app/controllers/meta_model/models_controller.rb +69 -0
  24. data/app/helpers/meta_model/application_helper.rb +10 -0
  25. data/app/helpers/meta_model/model_helper.rb +10 -0
  26. data/app/models/concerns/meta_model/model_base.rb +43 -0
  27. data/app/models/meta_model/has_association.rb +46 -0
  28. data/app/models/meta_model/meta_model_base.rb +7 -0
  29. data/app/models/meta_model/model.rb +51 -0
  30. data/app/models/meta_model/property.rb +11 -0
  31. data/app/serializers/meta_model/has_association_serializer.rb +13 -0
  32. data/app/serializers/meta_model/model_serializer.rb +11 -0
  33. data/app/serializers/meta_model/property_serializer.rb +6 -0
  34. data/app/views/layouts/meta_model.html.slim +28 -0
  35. data/app/views/meta_model/meta/associations/index.html.slim +12 -0
  36. data/app/views/meta_model/meta/index.html.slim +2 -0
  37. data/app/views/meta_model/meta/models/edit.html.slim +39 -0
  38. data/app/views/meta_model/models/_form.html.slim +72 -0
  39. data/app/views/meta_model/models/_has_many_association.html.slim +4 -0
  40. data/app/views/meta_model/models/_record_details.html.slim +13 -0
  41. data/app/views/meta_model/models/edit.html.slim +6 -0
  42. data/app/views/meta_model/models/index.html.slim +14 -0
  43. data/app/views/meta_model/models/meta_index.html.slim +6 -0
  44. data/app/views/meta_model/models/new.html.slim +7 -0
  45. data/app/views/meta_model/models/show.html.slim +18 -0
  46. data/config/initializers/active_model_serializer.rb +6 -0
  47. data/config/routes.rb +19 -0
  48. data/lib/ext/hash.rb +7 -0
  49. data/lib/meta_model/engine.rb +23 -0
  50. data/lib/meta_model/version.rb +3 -0
  51. data/lib/meta_model.rb +4 -0
  52. data/lib/meta_models.rb +70 -0
  53. data/lib/tasks/meta_model_tasks.rake +4 -0
  54. data/test/dummy/README.rdoc +28 -0
  55. data/test/dummy/Rakefile +6 -0
  56. data/test/dummy/app/assets/javascripts/application.js +14 -0
  57. data/test/dummy/app/assets/stylesheets/meta_model.css.scss +55 -0
  58. data/test/dummy/app/controllers/meta_model/application_controller.rb +8 -0
  59. data/test/dummy/app/helpers/application_helper.rb +2 -0
  60. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  61. data/test/dummy/bin/bundle +3 -0
  62. data/test/dummy/bin/rails +4 -0
  63. data/test/dummy/bin/rake +4 -0
  64. data/test/dummy/bin/setup +29 -0
  65. data/test/dummy/config/application.rb +29 -0
  66. data/test/dummy/config/boot.rb +5 -0
  67. data/test/dummy/config/database.yml +25 -0
  68. data/test/dummy/config/environment.rb +5 -0
  69. data/test/dummy/config/environments/development.rb +41 -0
  70. data/test/dummy/config/environments/production.rb +79 -0
  71. data/test/dummy/config/environments/test.rb +42 -0
  72. data/test/dummy/config/initializers/assets.rb +11 -0
  73. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  74. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  75. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  76. data/test/dummy/config/initializers/inflections.rb +16 -0
  77. data/test/dummy/config/initializers/mime_types.rb +4 -0
  78. data/test/dummy/config/initializers/session_store.rb +3 -0
  79. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  80. data/test/dummy/config/locales/en.yml +23 -0
  81. data/test/dummy/config/routes.rb +21 -0
  82. data/test/dummy/config/secrets.yml +22 -0
  83. data/test/dummy/config.ru +4 -0
  84. data/test/dummy/public/404.html +67 -0
  85. data/test/dummy/public/422.html +67 -0
  86. data/test/dummy/public/500.html +66 -0
  87. data/test/dummy/public/favicon.ico +0 -0
  88. data/test/integration/navigation_test.rb +10 -0
  89. data/test/meta_model_test.rb +7 -0
  90. data/test/test_helper.rb +19 -0
  91. data/vendor/assets/fonts/bootstrap/glyphicons-halflings-regular.eot +0 -0
  92. data/vendor/assets/fonts/bootstrap/glyphicons-halflings-regular.svg +288 -0
  93. data/vendor/assets/fonts/bootstrap/glyphicons-halflings-regular.ttf +0 -0
  94. data/vendor/assets/fonts/bootstrap/glyphicons-halflings-regular.woff +0 -0
  95. data/vendor/assets/fonts/bootstrap/glyphicons-halflings-regular.woff2 +0 -0
  96. data/vendor/assets/javascripts/backbone.js +1608 -0
  97. data/vendor/assets/javascripts/bootstrap/affix.js +162 -0
  98. data/vendor/assets/javascripts/bootstrap/alert.js +94 -0
  99. data/vendor/assets/javascripts/bootstrap/button.js +116 -0
  100. data/vendor/assets/javascripts/bootstrap/carousel.js +240 -0
  101. data/vendor/assets/javascripts/bootstrap/collapse.js +211 -0
  102. data/vendor/assets/javascripts/bootstrap/dropdown.js +161 -0
  103. data/vendor/assets/javascripts/bootstrap/modal.js +324 -0
  104. data/vendor/assets/javascripts/bootstrap/popover.js +119 -0
  105. data/vendor/assets/javascripts/bootstrap/scrollspy.js +175 -0
  106. data/vendor/assets/javascripts/bootstrap/tab.js +153 -0
  107. data/vendor/assets/javascripts/bootstrap/tooltip.js +478 -0
  108. data/vendor/assets/javascripts/bootstrap/transition.js +59 -0
  109. data/vendor/assets/javascripts/bootstrap-sprockets.js +12 -0
  110. data/vendor/assets/javascripts/bootstrap.js +2304 -0
  111. data/vendor/assets/javascripts/lodash.js +6785 -0
  112. data/vendor/assets/javascripts/rivets-backbone.js +97 -0
  113. data/vendor/assets/javascripts/rivets.js +1273 -0
  114. data/vendor/assets/javascripts/sightglass.js +203 -0
  115. data/vendor/assets/stylesheets/_bootstrap-compass.scss +7 -0
  116. data/vendor/assets/stylesheets/_bootstrap-mincer.scss +17 -0
  117. data/vendor/assets/stylesheets/_bootstrap-sprockets.scss +7 -0
  118. data/vendor/assets/stylesheets/_bootstrap.scss +50 -0
  119. data/vendor/assets/stylesheets/bootstrap/_alerts.scss +68 -0
  120. data/vendor/assets/stylesheets/bootstrap/_badges.scss +63 -0
  121. data/vendor/assets/stylesheets/bootstrap/_breadcrumbs.scss +26 -0
  122. data/vendor/assets/stylesheets/bootstrap/_button-groups.scss +243 -0
  123. data/vendor/assets/stylesheets/bootstrap/_buttons.scss +160 -0
  124. data/vendor/assets/stylesheets/bootstrap/_carousel.scss +267 -0
  125. data/vendor/assets/stylesheets/bootstrap/_close.scss +35 -0
  126. data/vendor/assets/stylesheets/bootstrap/_code.scss +69 -0
  127. data/vendor/assets/stylesheets/bootstrap/_component-animations.scss +38 -0
  128. data/vendor/assets/stylesheets/bootstrap/_dropdowns.scss +213 -0
  129. data/vendor/assets/stylesheets/bootstrap/_forms.scss +548 -0
  130. data/vendor/assets/stylesheets/bootstrap/_glyphicons.scss +236 -0
  131. data/vendor/assets/stylesheets/bootstrap/_grid.scss +84 -0
  132. data/vendor/assets/stylesheets/bootstrap/_input-groups.scss +166 -0
  133. data/vendor/assets/stylesheets/bootstrap/_jumbotron.scss +49 -0
  134. data/vendor/assets/stylesheets/bootstrap/_labels.scss +66 -0
  135. data/vendor/assets/stylesheets/bootstrap/_list-group.scss +124 -0
  136. data/vendor/assets/stylesheets/bootstrap/_media.scss +47 -0
  137. data/vendor/assets/stylesheets/bootstrap/_mixins.scss +39 -0
  138. data/vendor/assets/stylesheets/bootstrap/_modals.scss +148 -0
  139. data/vendor/assets/stylesheets/bootstrap/_navbar.scss +662 -0
  140. data/vendor/assets/stylesheets/bootstrap/_navs.scss +244 -0
  141. data/vendor/assets/stylesheets/bootstrap/_normalize.scss +427 -0
  142. data/vendor/assets/stylesheets/bootstrap/_pager.scss +54 -0
  143. data/vendor/assets/stylesheets/bootstrap/_pagination.scss +88 -0
  144. data/vendor/assets/stylesheets/bootstrap/_panels.scss +261 -0
  145. data/vendor/assets/stylesheets/bootstrap/_popovers.scss +135 -0
  146. data/vendor/assets/stylesheets/bootstrap/_print.scss +107 -0
  147. data/vendor/assets/stylesheets/bootstrap/_progress-bars.scss +87 -0
  148. data/vendor/assets/stylesheets/bootstrap/_responsive-embed.scss +35 -0
  149. data/vendor/assets/stylesheets/bootstrap/_responsive-utilities.scss +174 -0
  150. data/vendor/assets/stylesheets/bootstrap/_scaffolding.scss +150 -0
  151. data/vendor/assets/stylesheets/bootstrap/_tables.scss +234 -0
  152. data/vendor/assets/stylesheets/bootstrap/_theme.scss +272 -0
  153. data/vendor/assets/stylesheets/bootstrap/_thumbnails.scss +38 -0
  154. data/vendor/assets/stylesheets/bootstrap/_tooltip.scss +103 -0
  155. data/vendor/assets/stylesheets/bootstrap/_type.scss +298 -0
  156. data/vendor/assets/stylesheets/bootstrap/_utilities.scss +56 -0
  157. data/vendor/assets/stylesheets/bootstrap/_variables.scss +864 -0
  158. data/vendor/assets/stylesheets/bootstrap/_wells.scss +29 -0
  159. data/vendor/assets/stylesheets/bootstrap/mixins/_alerts.scss +14 -0
  160. data/vendor/assets/stylesheets/bootstrap/mixins/_background-variant.scss +11 -0
  161. data/vendor/assets/stylesheets/bootstrap/mixins/_border-radius.scss +18 -0
  162. data/vendor/assets/stylesheets/bootstrap/mixins/_buttons.scss +52 -0
  163. data/vendor/assets/stylesheets/bootstrap/mixins/_center-block.scss +7 -0
  164. data/vendor/assets/stylesheets/bootstrap/mixins/_clearfix.scss +22 -0
  165. data/vendor/assets/stylesheets/bootstrap/mixins/_forms.scss +88 -0
  166. data/vendor/assets/stylesheets/bootstrap/mixins/_gradients.scss +58 -0
  167. data/vendor/assets/stylesheets/bootstrap/mixins/_grid-framework.scss +81 -0
  168. data/vendor/assets/stylesheets/bootstrap/mixins/_grid.scss +122 -0
  169. data/vendor/assets/stylesheets/bootstrap/mixins/_hide-text.scss +21 -0
  170. data/vendor/assets/stylesheets/bootstrap/mixins/_image.scss +33 -0
  171. data/vendor/assets/stylesheets/bootstrap/mixins/_labels.scss +12 -0
  172. data/vendor/assets/stylesheets/bootstrap/mixins/_list-group.scss +31 -0
  173. data/vendor/assets/stylesheets/bootstrap/mixins/_nav-divider.scss +10 -0
  174. data/vendor/assets/stylesheets/bootstrap/mixins/_nav-vertical-align.scss +9 -0
  175. data/vendor/assets/stylesheets/bootstrap/mixins/_opacity.scss +8 -0
  176. data/vendor/assets/stylesheets/bootstrap/mixins/_pagination.scss +23 -0
  177. data/vendor/assets/stylesheets/bootstrap/mixins/_panels.scss +24 -0
  178. data/vendor/assets/stylesheets/bootstrap/mixins/_progress-bar.scss +10 -0
  179. data/vendor/assets/stylesheets/bootstrap/mixins/_reset-filter.scss +8 -0
  180. data/vendor/assets/stylesheets/bootstrap/mixins/_resize.scss +6 -0
  181. data/vendor/assets/stylesheets/bootstrap/mixins/_responsive-visibility.scss +21 -0
  182. data/vendor/assets/stylesheets/bootstrap/mixins/_size.scss +10 -0
  183. data/vendor/assets/stylesheets/bootstrap/mixins/_tab-focus.scss +9 -0
  184. data/vendor/assets/stylesheets/bootstrap/mixins/_table-row.scss +28 -0
  185. data/vendor/assets/stylesheets/bootstrap/mixins/_text-emphasis.scss +11 -0
  186. data/vendor/assets/stylesheets/bootstrap/mixins/_text-overflow.scss +8 -0
  187. data/vendor/assets/stylesheets/bootstrap/mixins/_vendor-prefixes.scss +222 -0
  188. metadata +365 -0
@@ -0,0 +1,80 @@
1
+ module MetaModel
2
+ module Meta
3
+ class ModelsController < ApplicationController
4
+ before_action :get_model, only: [:edit, :show, :update, :destroy]
5
+
6
+ def index
7
+ respond_to do |format|
8
+ format.html { @hierarchy = Model.all.hierarchically }
9
+ format.json { render json: Model.all }
10
+ end
11
+ end
12
+
13
+ def hierarchy
14
+ respond_to do |format|
15
+ format.json { render json: Model.all.hierarchically }
16
+ end
17
+ end
18
+
19
+ def show
20
+ respond_to do |format|
21
+ format.json do
22
+ render json: @model
23
+ end
24
+ end
25
+ end
26
+
27
+ def edit
28
+ @models = Model.all.order(:name)
29
+ end
30
+
31
+ def create
32
+ model = Model.create(model_params)
33
+
34
+ create_models
35
+
36
+ render json: model
37
+ end
38
+
39
+ def update
40
+ model_params.each do |key, value|
41
+ @model.send("#{key}=", value)
42
+ end
43
+ @model.save
44
+
45
+ create_models
46
+
47
+ render json: @model
48
+ end
49
+
50
+ def destroy
51
+ @model.destroy
52
+
53
+ create_models
54
+
55
+ render json: nil
56
+ end
57
+
58
+ private
59
+
60
+ def get_model
61
+ @model = if model_param_class_name
62
+ Model.where(class_name: model_param_class_name).first
63
+ end || Model.find(params[:id])
64
+ end
65
+
66
+ def model_param_class_name
67
+ if params[:id]
68
+ @model_param_class_name ||= params[:id].classify
69
+ end
70
+ rescue NameError
71
+ end
72
+
73
+ def model_params
74
+ superclass_model = params[:model].delete(:superclass_model_id)
75
+ params.require(:model).permit(:class_name, :superclass_model).merge(superclass_model: superclass_model)
76
+ end
77
+ end
78
+ end
79
+ end
80
+
@@ -0,0 +1,36 @@
1
+ module MetaModel
2
+ module Meta
3
+ class PropertiesController < ApplicationController
4
+ before_action :get_property, only: [:edit, :show, :update, :destroy]
5
+
6
+ def destroy
7
+ @property.destroy
8
+
9
+ render json: nil
10
+ end
11
+
12
+ def create
13
+ property = Property.create(property_params)
14
+
15
+ render json: property
16
+ end
17
+
18
+ def update
19
+ @property.update_attributes(property_params)
20
+
21
+ render json: @property
22
+ end
23
+
24
+ private
25
+
26
+ def get_property
27
+ @property = Property.find(params[:id])
28
+ end
29
+
30
+ def property_params
31
+ model = params[:property].delete(:model_id)
32
+ params.require(:property).permit(:name, :type).merge(model: model)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,7 @@
1
+ module MetaModel
2
+ class MetaController < ApplicationController
3
+ def index
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,69 @@
1
+ module MetaModel
2
+ class ModelsController < MetaModel::ApplicationController
3
+ before_action :get_model
4
+ before_action :get_meta_model
5
+ before_action :get_record, only: [:show, :edit, :update]
6
+
7
+ layout 'layouts/meta_model'
8
+ def meta_index
9
+ @hierarchy = Model.order(:class_name).hierarchically
10
+ end
11
+
12
+ def index
13
+ @records = @model.all.to_a
14
+ respond_to do |format|
15
+ format.html
16
+ format.json { render json: @records, root: :records }
17
+ end
18
+ end
19
+
20
+ def show
21
+ end
22
+
23
+ def edit
24
+ end
25
+
26
+ def update
27
+ @record.update_attributes(params[:data])
28
+
29
+ redirect_to action: :show
30
+ end
31
+
32
+ def new
33
+ @record = @model.new
34
+ end
35
+
36
+ def create
37
+ record = @model.create(params[:data])
38
+
39
+ redirect_to action: :show, id: record.id
40
+ end
41
+
42
+ def destroy
43
+ @record.destroy
44
+
45
+ redirect_to action: :index, model: params[:model]
46
+ end
47
+
48
+ private
49
+
50
+ def get_record
51
+ @record = @model.find(params[:id])
52
+ end
53
+
54
+ def get_meta_model
55
+ @meta_model = Model.where(class_name: model_param_class_name).first if model_param_class_name
56
+ end
57
+
58
+ def get_model
59
+ @model = "MetaModel::#{model_param_class_name}".constantize if model_param_class_name
60
+ end
61
+
62
+ def model_param_class_name
63
+ if params[:model]
64
+ @model_param_class_name ||= params[:model].classify
65
+ end
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,10 @@
1
+ module MetaModel
2
+ module ApplicationHelper
3
+ def action_and_controller_javascript_include_tag
4
+ capture do
5
+ concat javascript_include_tag controller_path if Rails.root.join("app/assets/javascripts/#{controller_path}.js.coffee").exist?
6
+ concat javascript_include_tag "#{controller_path}/#{action_name}" if Rails.root.join("app/assets/javascripts/#{controller_path}/#{action_name}.js.coffee").exist?
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module MetaModel
2
+ module ModelHelper
3
+ def hierarchical_render(hierarchy, level = 0, &block)
4
+ hierarchy.each do |object, sub_hierarchy|
5
+ block.call object, level
6
+ hierarchical_render(sub_hierarchy, level + 1, &block)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,43 @@
1
+ module MetaModel
2
+ module ModelBase
3
+ extend ActiveSupport::Concern
4
+
5
+ LOADED_CLASSES = []
6
+ included do |base|
7
+ LOADED_CLASSES << self
8
+ end
9
+
10
+ module ClassMethods
11
+ def inherited(base)
12
+ LOADED_CLASSES << base
13
+ end
14
+
15
+ def meta_model_class
16
+ name.gsub(/^MetaModel::/, '')
17
+ end
18
+
19
+ def naming_column
20
+ # Probably want to allow the user to choose this
21
+ MetaModel::Model.where(class_name: meta_model_class).first.properties.detect {|p| p.type == 'String' }.name
22
+ end
23
+ end
24
+
25
+ def naming_column_value
26
+ self.read_attribute(self.class.naming_column)
27
+ end
28
+
29
+ def meta_model_class
30
+ self.class.meta_model_class
31
+ end
32
+
33
+ def association_values
34
+ self.class.associations.each_with_object({}) do |(key, _), result|
35
+ result[key] = self.send(key)
36
+ end
37
+ end
38
+
39
+ def _description
40
+ self.try(:name) || self.try(:name) || self.try(:description) || self.id
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,46 @@
1
+ module MetaModel
2
+ class HasAssociation
3
+ include Neo4j::ActiveRel
4
+
5
+ from_class 'MetaModel::Model'
6
+ to_class 'MetaModel::Model'
7
+ type 'has_association_to'
8
+
9
+
10
+ # one_to_many refers to from_class has_many to_classes
11
+ # many_to_one refers to from_class has_one to_class
12
+ property :join_type, type: String
13
+ validates_inclusion_of :join_type, :in => %w( many_to_one one_to_many many_to_many )
14
+
15
+ # Name of associations on each side
16
+ property :name, type: String
17
+ property :opposite_name, type: String
18
+
19
+ property :relationship_type, type: String
20
+
21
+ def from_model
22
+ from_node
23
+ end
24
+
25
+ def to_model
26
+ to_node
27
+ end
28
+
29
+ def from_model=(other)
30
+ self.from_node = other
31
+ end
32
+
33
+ def to_model=(other)
34
+ self.to_node = other
35
+ end
36
+
37
+ def from_model_id=(id)
38
+ self.from_model = Model.find(id)
39
+ end
40
+
41
+ def to_model_id=(id)
42
+ self.to_model = Model.find(id)
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,7 @@
1
+ module MetaModel
2
+ class MetaModelBase
3
+ include Neo4j::ActiveNode
4
+ include ActiveModel::Serialization
5
+
6
+ end
7
+ end
@@ -0,0 +1,51 @@
1
+ module MetaModel
2
+ class Model < MetaModelBase
3
+ property :class_name, type: String
4
+
5
+ has_one :out, :superclass_model, type: :inherits_from, model_class: 'MetaModel::Model'
6
+
7
+ has_one :out, :id_property, type: :has_id_property, model_class: 'MetaModel::Property'
8
+ has_many :out, :properties, type: :has_property, model_class: 'MetaModel::Property'
9
+
10
+ has_many :both, :assocs, model_class: 'MetaModel::Model', rel_class: 'MetaModel::HasAssociation'
11
+
12
+ before_destroy :destroy_properties
13
+
14
+ def to_param
15
+ self.class_name.tableize
16
+ end
17
+
18
+ # def property_ids
19
+ # properties(:p).pluck(p: :uuid)
20
+ # end
21
+
22
+ def has_associations
23
+ assocs.each_rel.to_a
24
+ end
25
+
26
+ def self.hierarchically
27
+ Hash.new.tap do |result|
28
+ model_parents = Hash[*all.query_as(:model).optional_match("model-[:inherits_from]->(parent)").pluck(:model, :parent).flatten]
29
+
30
+ all.query_as(:model).where('NOT(model-[:inherits_from]->())').pluck(:model).each do |model|
31
+ result[model] = {}
32
+ end
33
+
34
+ all.query_as(:model).match('p=model-[:inherits_from*1..]->()').pluck('nodes(p)').each do |path|
35
+ path.reverse.inject(result) do |sub_result, model|
36
+ sub_result[model] ||= {}
37
+ sub_result[model]
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def destroy_properties
47
+ properties.each(&:destroy)
48
+ id_property.try(:destroy)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,11 @@
1
+ module MetaModel
2
+ class Property < MetaModelBase
3
+ property :name, type: String
4
+ property :type, type: String
5
+
6
+ validates_inclusion_of :type, :in => %w( String DateTime Boolean Integer )
7
+
8
+ has_one :in, :model, origin: :properties, model_class: 'MetaModel::Model'
9
+
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module MetaModel
2
+ class HasAssociationSerializer < ActiveModel::Serializer
3
+ attributes :id, :join_type, :name, :opposite_name, :relationship_type, :from_model, :to_model
4
+
5
+ def from_model
6
+ object.from_node.id
7
+ end
8
+
9
+ def to_model
10
+ object.to_node.id
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module MetaModel
2
+ class ModelSerializer < ActiveModel::Serializer
3
+ attributes :id, :class_name
4
+
5
+ # embed :ids, include: true
6
+
7
+ has_many :properties
8
+ has_many :has_associations
9
+ # has_one :superclass_model
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ module MetaModel
2
+ class PropertySerializer < ActiveModel::Serializer
3
+ attributes :id, :name, :type
4
+ end
5
+ end
6
+
@@ -0,0 +1,28 @@
1
+ doctype html
2
+ html
3
+ head
4
+ title MetaModel
5
+
6
+ javascript:
7
+ var meta_model_root_path = '#{root_path}';
8
+
9
+ = stylesheet_link_tag 'meta_model', media: 'all'
10
+ = javascript_include_tag 'meta_model'
11
+
12
+ = csrf_meta_tags
13
+
14
+ body
15
+ nav.navbar.navbar-default role="navigation"
16
+ .container-fluid
17
+ ul.nav.navbar-nav
18
+ li
19
+ = link_to 'Models', root_path
20
+
21
+ li
22
+ = link_to 'Admin', meta_path
23
+
24
+ .container
25
+ = yield
26
+
27
+ = action_and_controller_javascript_include_tag
28
+
@@ -0,0 +1,12 @@
1
+
2
+ table
3
+ - @has_associations.each do |has_association|
4
+ tr
5
+ td = link_to 'Edit', action: :edit, id: has_association.id
6
+ td = has_association.from_node.class_name
7
+ td -
8
+ td = has_association.relationship_type
9
+ td = has_association.join_type
10
+ td ->
11
+ td = has_association.to_node.class_name
12
+
@@ -0,0 +1,2 @@
1
+
2
+ #ember-application
@@ -0,0 +1,39 @@
1
+ = form_tag({action: :update}, method: :put, class: 'form-horizontal', role: :form) do
2
+
3
+ .form-group
4
+ label
5
+ .col-sm-2.control-label Class Name
6
+ .col-sm-10 = text_field_tag 'model_data[class_name]', @model.class_name, class: 'form-control'
7
+
8
+ .form-group
9
+ label
10
+ .col-sm-2.control-label Inherits from
11
+ .col-sm-10 = select_tag 'model_data[superclass_model]', options_from_collection_for_select(([OpenStruct.new] + @models.to_a), 'class_name', 'class_name', @model.superclass_model.try(:class_name)), class: 'form-control'
12
+
13
+ .properties.row
14
+ h2
15
+ | Properties
16
+ a.add.btn.btn-default Add Property
17
+
18
+ - @model.properties.each do |property|
19
+ .well.property.col-sm-6
20
+ i.glyphicon.glyphicon-remove-circle.close.pull-right
21
+
22
+ .form-group
23
+ label
24
+ .col-sm-2.control-label Name
25
+ .col-sm-10 = text_field_tag 'model_data[properties][][name]', property.name, class: 'form-control'
26
+
27
+ .form-group
28
+ label
29
+ .col-sm-2.control-label Type
30
+ .col-sm-10 = select_tag 'model_data[properties][][type]', options_for_select(['String', 'DateTime'], property.type), class: 'form-control'
31
+
32
+
33
+ .form-group
34
+ = submit_tag 'Update', class: 'btn btn-primary'
35
+
36
+ scss:
37
+ label {
38
+ width: 100%;
39
+ }
@@ -0,0 +1,72 @@
1
+ - record.attributes.each do |key, value|
2
+ .form-group
3
+ label.control-label.col-sm-2 = key.humanize
4
+ .col-sm-10 = text_field_tag "data[#{key}]", value, class: 'form-control'
5
+
6
+ - record.class.associations.each do |key, association|
7
+ .form-group
8
+ label.control-label.col-sm-2 = key.to_s.humanize
9
+ .col-sm-10
10
+ - case association.type
11
+ - when :has_one
12
+ = select_tag "data[#{key}]", options_from_collection_for_select(association.target_class.all.to_a, :id, :naming_column_value, record.send(key).id), class: 'form-control'
13
+ - when :has_many
14
+ .has-many-association data-option-type="#{association.target_class.meta_model_class.tableize.singularize}" data-options="#{association.target_class.all.to_json(methods: :naming_column_value)}"
15
+ select.form-control rv-on-change="view.add"
16
+ option Please select
17
+ option rv-each-option="view.current_options < objects" rv-value="option.id"
18
+ | { option.naming_column_value }
19
+
20
+ .list-group
21
+ a.list-group-item rv-each-object="objects < objects" rv-data-id="object.id" rv-on-click="view.delete"
22
+ input type="hidden" name="data[#{key}][]" rv-value="object.id"
23
+ | { object.naming_column_value }
24
+
25
+
26
+
27
+ coffee:
28
+
29
+ class HasManyAssociationView extends Backbone.View
30
+ el: '.has-many-association'
31
+
32
+ initialize: ->
33
+ el = $(@el)
34
+ @options = _(el.data('options')).map((element) ->
35
+ element[el.data('option-type')]
36
+ ).value()
37
+
38
+ @objects = [@options[0]]
39
+
40
+ render: ->
41
+ @binding = rivets.bind $(@el), {@objects, view: @}
42
+
43
+ @
44
+
45
+ remove: ->
46
+ @binding.unbind()
47
+
48
+ current_options: =>
49
+ console.log('current_options!');
50
+ _(@options).difference(@objects).value()
51
+
52
+
53
+ add: (event, object) =>
54
+ selected_id = $(event.target).val()
55
+ selected_option = _(@options).find((option) -> option.id is selected_id)
56
+
57
+ @objects.push selected_option
58
+
59
+ $(@el).find('select option').removeAttr('selected')
60
+
61
+ delete: (event, object) =>
62
+ selected_id = $(event.target).data('id')
63
+ selected_object = _(@options).find((option) -> option.id is selected_id)
64
+
65
+ index = _(@objects).indexOf(selected_object)
66
+ @objects.removeAt(index)
67
+
68
+ ready = ->
69
+ new HasManyAssociationView().render()
70
+
71
+ $('document').ready ready
72
+ $('document').on 'page:load', ready
@@ -0,0 +1,4 @@
1
+ ul
2
+ - record.send(key).each do |object|
3
+ li = object.naming_column_value
4
+
@@ -0,0 +1,13 @@
1
+ - link ||= false
2
+
3
+ = link_to 'View', {action: :show, model: record.meta_model_class.to_s.tableize, id: record.id}, class: 'btn btn-default' if link
4
+
5
+ = link_to 'Edit', {action: :edit, model: record.meta_model_class.to_s.tableize, id: record.id}, class: 'btn btn-default'
6
+
7
+ = button_to 'Delete', {action: :destroy, model: record.meta_model_class.to_s.tableize, id: record.id}, method: :delete, class: 'btn btn-danger pull-right'
8
+
9
+ dl.dl-horizontal
10
+ - record.attributes.each do |key, value|
11
+ dt = key
12
+ dd = value
13
+
@@ -0,0 +1,6 @@
1
+
2
+ = form_tag({action: :update}, method: 'put', class: 'form-horizontal', role: 'form') do
3
+ = render partial: 'form', locals: {record: @record}
4
+
5
+ .form-group
6
+ = submit_tag 'Update', class: 'btn btn-primary'
@@ -0,0 +1,14 @@
1
+ ol.breadcrumb
2
+ li = link_to 'Models', root_path
3
+ li = @meta_model.class_name.pluralize
4
+
5
+ h2 = @meta_model.class_name.pluralize
6
+
7
+ = link_to 'Add', new_model_path(model: @meta_model)
8
+
9
+ div.list-group
10
+ - @records.each do |record|
11
+ = link_to model_path(id: record), class: 'list-group-item' do
12
+ - if record.class != @model
13
+ span.badge = record.class.to_s
14
+ = record._description
@@ -0,0 +1,6 @@
1
+ h2 Models
2
+
3
+ div.list-group
4
+ - hierarchical_render(@hierarchy) do |model, level|
5
+ = link_to ('&nbsp;&nbsp;&nbsp;' * level).html_safe + model.class_name, models_path(model: model), class: 'list-group-item'
6
+
@@ -0,0 +1,7 @@
1
+
2
+ = form_tag({action: :create}, method: 'post', class: 'form-horizontal', role: 'form') do
3
+ = render partial: 'form', locals: {record: @record}
4
+
5
+ .form-group
6
+ = submit_tag 'Create', class: 'btn btn-primary'
7
+
@@ -0,0 +1,18 @@
1
+ ol.breadcrumb
2
+ li = link_to 'Models', root_path
3
+ li = link_to @meta_model.class_name.pluralize, models_path(model: @meta_model.class_name)
4
+ li = @record._description
5
+
6
+ = render partial: 'record_details', locals: {record: @record}
7
+
8
+ - @model.associations.each do |name, association|
9
+ - logger.warn "@record: #{@record.inspect}"
10
+ - logger.warn "name: #{name.inspect}"
11
+ - result = @record.send(name)
12
+ - result = result.respond_to?(:each) ? result.to_a : (result ? [result] : [])
13
+ - if result.present?
14
+ h2 = name.to_s.humanize
15
+ div
16
+ - result.each do |sub_record|
17
+ = render partial: 'record_details', locals: {record: sub_record, link: true}
18
+
@@ -0,0 +1,6 @@
1
+ require 'active_model_serializers'
2
+
3
+ ActiveModel::Serializer.setup do |config|
4
+ config.embed = :ids
5
+ config.embed_in_root = true
6
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,19 @@
1
+ MetaModel::Engine.routes.draw do
2
+ namespace :meta do
3
+ resources :models do
4
+ collection do
5
+ get :hierarchy
6
+ end
7
+ end
8
+ resources :properties
9
+ resources :has_associations#, path: '/associations'#, param: :asso
10
+ end
11
+
12
+ get '/meta' => 'meta#index'
13
+
14
+
15
+ resources :models, path: '/:model'
16
+
17
+ root 'models#meta_index'#, as: :meta_models
18
+ end
19
+