trestle 0.8.3 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/trestle/_confirmation.js +23 -0
  3. data/app/assets/javascripts/trestle/_datepicker.js +22 -0
  4. data/app/assets/javascripts/trestle/_errors.js +11 -0
  5. data/app/assets/javascripts/trestle/_form.js +6 -0
  6. data/app/assets/javascripts/trestle/_gallery.js +27 -0
  7. data/app/assets/javascripts/trestle/_select.js +11 -0
  8. data/app/assets/javascripts/trestle/_sidebar.js +52 -0
  9. data/app/assets/javascripts/trestle/_table.js +21 -0
  10. data/app/assets/javascripts/trestle/_tabs.js +13 -0
  11. data/app/assets/javascripts/trestle/_tooltips.js +3 -0
  12. data/app/assets/javascripts/trestle/admin.js +23 -0
  13. data/app/assets/javascripts/trestle/custom.js +4 -0
  14. data/app/assets/stylesheets/trestle/components/_table.scss +6 -0
  15. data/app/helpers/trestle/form_helper.rb +1 -1
  16. data/app/helpers/trestle/format_helper.rb +48 -0
  17. data/app/helpers/trestle/url_helper.rb +2 -8
  18. data/app/views/layouts/trestle/admin.html.erb +3 -3
  19. data/app/views/trestle/admin/index.html.erb +1 -1
  20. data/app/views/trestle/dashboard/index.html.erb +2 -2
  21. data/app/views/trestle/resource/_form.html.erb +1 -1
  22. data/app/views/trestle/resource/edit.html.erb +2 -2
  23. data/app/views/trestle/resource/index.html.erb +1 -1
  24. data/app/views/trestle/resource/new.html.erb +1 -1
  25. data/app/views/trestle/resource/show.html.erb +2 -2
  26. data/app/views/trestle/shared/_sidebar.html.erb +4 -2
  27. data/bower.json +1 -1
  28. data/config/locales/en.yml +16 -2
  29. data/lib/generators/trestle/install/install_generator.rb +3 -3
  30. data/lib/generators/trestle/install/templates/custom.js +7 -0
  31. data/lib/generators/trestle/install/templates/trestle.rb.erb +3 -2
  32. data/lib/trestle/adapters.rb +7 -64
  33. data/lib/trestle/adapters/active_record_adapter.rb +46 -20
  34. data/lib/trestle/adapters/adapter.rb +176 -0
  35. data/lib/trestle/adapters/sequel_adapter.rb +85 -0
  36. data/lib/trestle/admin.rb +1 -1
  37. data/lib/trestle/attribute.rb +14 -37
  38. data/lib/trestle/breadcrumb.rb +6 -0
  39. data/lib/trestle/configuration.rb +1 -1
  40. data/lib/trestle/form/automatic.rb +29 -21
  41. data/lib/trestle/form/builder.rb +4 -0
  42. data/lib/trestle/form/field.rb +2 -2
  43. data/lib/trestle/form/fields/check_box.rb +1 -1
  44. data/lib/trestle/form/fields/collection_select.rb +1 -1
  45. data/lib/trestle/form/fields/date_select.rb +1 -1
  46. data/lib/trestle/form/fields/datetime_select.rb +1 -1
  47. data/lib/trestle/form/fields/grouped_collection_select.rb +1 -1
  48. data/lib/trestle/form/fields/select.rb +2 -2
  49. data/lib/trestle/form/fields/tag_select.rb +1 -2
  50. data/lib/trestle/form/fields/time_select.rb +1 -1
  51. data/lib/trestle/form/fields/time_zone_select.rb +1 -1
  52. data/lib/trestle/resource.rb +11 -7
  53. data/lib/trestle/resource/builder.rb +2 -1
  54. data/lib/trestle/resource/controller.rb +61 -17
  55. data/lib/trestle/scope.rb +1 -1
  56. data/lib/trestle/table/automatic.rb +5 -11
  57. data/lib/trestle/table/builder.rb +1 -0
  58. data/lib/trestle/table/column.rb +24 -43
  59. data/lib/trestle/version.rb +1 -1
  60. data/trestle.gemspec +3 -4
  61. data/vendor/assets/bower_components/trestle/flatpickr/dist/flatpickr.css +51 -26
  62. data/vendor/assets/bower_components/trestle/flatpickr/dist/flatpickr.js +349 -299
  63. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ar.js +5 -5
  64. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/bg.js +5 -5
  65. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/bn.js +5 -5
  66. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/cat.js +7 -7
  67. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/cs.js +7 -7
  68. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/cy.js +7 -7
  69. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/da.js +6 -6
  70. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/de.js +10 -10
  71. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/eo.js +11 -11
  72. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/es.js +7 -7
  73. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/et.js +11 -11
  74. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/fa.js +6 -6
  75. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/fi.js +7 -7
  76. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/fr.js +11 -11
  77. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/gr.js +13 -13
  78. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/he.js +5 -5
  79. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/hi.js +5 -5
  80. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/hr.js +6 -6
  81. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/hu.js +10 -10
  82. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/id.js +7 -7
  83. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/index.js +97 -0
  84. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/it.js +10 -10
  85. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ja.js +5 -5
  86. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ko.js +6 -6
  87. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/lt.js +10 -10
  88. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/lv.js +6 -6
  89. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/mk.js +8 -8
  90. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ms.js +7 -7
  91. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/my.js +7 -7
  92. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/nl.js +11 -11
  93. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/no.js +11 -11
  94. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/pa.js +5 -5
  95. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/pl.js +6 -6
  96. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/pt.js +6 -8
  97. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ro.js +7 -9
  98. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ru.js +6 -8
  99. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/si.js +5 -7
  100. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sk.js +8 -8
  101. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sl.js +8 -10
  102. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sq.js +5 -7
  103. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sr.js +9 -10
  104. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sv.js +8 -10
  105. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/th.js +10 -11
  106. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/tr.js +6 -8
  107. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/uk.js +6 -7
  108. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/vn.js +6 -8
  109. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/zh.js +9 -11
  110. metadata +24 -34
  111. data/app/assets/javascripts/trestle/_confirmation.js.coffee +0 -18
  112. data/app/assets/javascripts/trestle/_datepicker.js.coffee +0 -18
  113. data/app/assets/javascripts/trestle/_errors.js.coffee +0 -8
  114. data/app/assets/javascripts/trestle/_form.js.coffee +0 -4
  115. data/app/assets/javascripts/trestle/_gallery.js.coffee +0 -21
  116. data/app/assets/javascripts/trestle/_select.js.coffee +0 -7
  117. data/app/assets/javascripts/trestle/_sidebar.js.coffee +0 -45
  118. data/app/assets/javascripts/trestle/_table.js.coffee +0 -16
  119. data/app/assets/javascripts/trestle/_tabs.js.coffee +0 -9
  120. data/app/assets/javascripts/trestle/_tooltips.js.coffee +0 -2
  121. data/app/assets/javascripts/trestle/admin.js.coffee +0 -22
  122. data/app/assets/javascripts/trestle/custom.js.coffee +0 -4
  123. data/lib/generators/trestle/install/templates/custom.js.coffee +0 -7
data/bower.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "ionicons": "~2.0.1",
9
9
  "magnific-popup": "~1.1.0",
10
10
  "bootstrap-confirmation2": "~2.4.0",
11
- "flatpickr": "~2.6.1",
11
+ "flatpickr": "~3.0.7",
12
12
  "select2": "~4.0.3",
13
13
  "select2-bootstrap-theme": "~0.1.0"
14
14
  }
@@ -28,6 +28,12 @@ en:
28
28
  more_pages:
29
29
  display_entries: "Displaying %{entry_name} <strong>%{first}&nbsp;-&nbsp;%{last}</strong> of <b>%{total}</b>"
30
30
 
31
+ onboarding:
32
+ welcome: Welcome to Trestle
33
+ no_admins: To begin, please create an admin within <code>app/admin</code>.
34
+ no_template: To customize this template, please create <code>%{path}</code>.
35
+ no_form: Please define a form block or create a <code>_form.html</code> partial.
36
+
31
37
  admin:
32
38
  titles:
33
39
  index: Listing %{pluralized_model_name}
@@ -44,10 +50,18 @@ en:
44
50
  headers:
45
51
  id: ID
46
52
 
47
- column:
48
- blank: None
53
+ form:
54
+ select:
55
+ prompt: "- Select %{attribute_name} -"
49
56
 
50
57
  confirmation:
51
58
  title: Are you sure?
52
59
  delete: Delete
53
60
  cancel: Cancel
61
+
62
+ ui:
63
+ toggle_navigation: Toggle navigation
64
+ toggle_sidebar: Toggle sidebar
65
+
66
+ format:
67
+ blank: None
@@ -10,10 +10,10 @@ module Trestle
10
10
  end
11
11
 
12
12
  def create_assets
13
- template "_variables.scss", "app/assets/stylesheets/trestle/_variables.scss"
14
- template "_custom.scss", "app/assets/stylesheets/trestle/_custom.scss"
13
+ template "_variables.scss", "app/assets/stylesheets/trestle/_variables.scss"
14
+ template "_custom.scss", "app/assets/stylesheets/trestle/_custom.scss"
15
15
 
16
- template "custom.js.coffee", "app/assets/javascripts/trestle/custom.js.coffee"
16
+ template "custom.js", "app/assets/javascripts/trestle/custom.js"
17
17
  end
18
18
 
19
19
  def create_directory
@@ -0,0 +1,7 @@
1
+ // This file may be used for providing additional customizations to the Trestle
2
+ // admin. It will be automatically included within all admin pages.
3
+ //
4
+ // For organizational purposes, you may wish to define your customizations
5
+ // within individual partials and `require` them here.
6
+ //
7
+ // e.g. //= require "trestle/custom/my_custom_js"
@@ -70,7 +70,7 @@ Trestle.configure do |config|
70
70
  # config.around_action do |controller, block|
71
71
  # Rails.logger.debug("Around action (before)")
72
72
  # block.call
73
- # Rails.logger.debug("Around ation (after)")
73
+ # Rails.logger.debug("Around action (after)")
74
74
  # end
75
75
 
76
76
  # Specify a custom hook to be injected into the admin.
@@ -93,7 +93,8 @@ Trestle.configure do |config|
93
93
  # See the documentation on Trestle::Adapters::Adapter for details on
94
94
  # the adapter methods that can be customized.
95
95
  #
96
- # config.default_adapter.extend MyAdapterExtensions
96
+ # config.default_adapter = Trestle::Adapters.compose(Trestle::Adapters::SequelAdapter)
97
+ # config.default_adapter.include MyAdapterExtensions
97
98
 
98
99
  # Register a form field type to be made available to the Trestle form builder.
99
100
  # Field types should conform to the following method definition:
@@ -2,73 +2,16 @@ module Trestle
2
2
  module Adapters
3
3
  extend ActiveSupport::Autoload
4
4
 
5
+ autoload :Adapter
6
+
5
7
  autoload :ActiveRecordAdapter
6
8
  autoload :DraperAdapter
9
+ autoload :SequelAdapter
7
10
 
8
- class Adapter
9
- attr_reader :admin
10
-
11
- def initialize(admin)
12
- @admin = admin
13
- end
14
-
15
- def collection(params={})
16
- raise NotImplementedError
17
- end
18
-
19
- def find_instance(params)
20
- raise NotImplementedError
21
- end
22
-
23
- def build_instance(params={})
24
- raise NotImplementedError
25
- end
26
-
27
- def update_instance(instance, params)
28
- raise NotImplementedError
29
- end
30
-
31
- def save_instance(instance)
32
- raise NotImplementedError
33
- end
34
-
35
- def delete_instance(instance)
36
- raise NotImplementedError
37
- end
38
-
39
- def decorate_collection(collection)
40
- collection
41
- end
42
-
43
- def merge_scopes(scope, other)
44
- raise NotImplementedError
45
- end
46
-
47
- def sort(collection, params)
48
- raise NotImplementedError
49
- end
50
-
51
- def paginate(collection, params)
52
- raise NotImplementedError
53
- end
54
-
55
- def count(collection)
56
- raise NotImplementedError
57
- end
58
-
59
- def permitted_params(params)
60
- params.require(admin.admin_name.singularize).permit!
61
- end
62
-
63
- def default_attributes
64
- raise NotImplementedError
65
- end
66
-
67
- # Creates a new Adapter class with the given modules mixed in
68
- def self.compose(*modules)
69
- Class.new(self) do
70
- modules.each { |mod| include(mod) }
71
- end
11
+ # Creates a new Adapter class with the given modules mixed in
12
+ def self.compose(*modules)
13
+ Class.new(Adapter) do
14
+ modules.each { |mod| include(mod) }
72
15
  end
73
16
  end
74
17
  end
@@ -2,19 +2,19 @@ module Trestle
2
2
  module Adapters
3
3
  module ActiveRecordAdapter
4
4
  def collection(params={})
5
- admin.model.all
5
+ model.all
6
6
  end
7
7
 
8
8
  def find_instance(params)
9
- admin.model.find(params[:id])
9
+ model.find(params[:id])
10
10
  end
11
11
 
12
- def build_instance(params={})
13
- admin.model.new(params)
12
+ def build_instance(attrs={}, params={})
13
+ model.new(attrs)
14
14
  end
15
15
 
16
- def update_instance(instance, params)
17
- instance.assign_attributes(params)
16
+ def update_instance(instance, attrs, params={})
17
+ instance.assign_attributes(attrs)
18
18
  end
19
19
 
20
20
  def save_instance(instance)
@@ -25,10 +25,6 @@ module Trestle
25
25
  instance.destroy
26
26
  end
27
27
 
28
- def to_param(instance)
29
- instance
30
- end
31
-
32
28
  def unscope(scope)
33
29
  scope.unscoped
34
30
  end
@@ -37,27 +33,57 @@ module Trestle
37
33
  scope.merge(other)
38
34
  end
39
35
 
36
+ def count(collection)
37
+ collection.count
38
+ end
39
+
40
40
  def sort(collection, field, order)
41
41
  collection.reorder(field => order)
42
42
  end
43
43
 
44
- def paginate(collection, params)
45
- collection = Kaminari.paginate_array(collection) unless collection.respond_to?(:page)
46
- collection.page(params[:page])
44
+ def human_attribute_name(attribute, options={})
45
+ model.human_attribute_name(attribute, options)
47
46
  end
48
47
 
49
- def count(collection)
50
- collection.count
48
+ def default_table_attributes
49
+ default_attributes.reject do |attribute|
50
+ inheritance_column?(attribute) || counter_cache_column?(attribute)
51
+ end
51
52
  end
52
53
 
54
+ def default_form_attributes
55
+ default_attributes.reject do |attribute|
56
+ primary_key?(attribute) || inheritance_column?(attribute) || counter_cache_column?(attribute)
57
+ end
58
+ end
59
+
60
+ protected
53
61
  def default_attributes
54
- admin.model.columns.map do |column|
55
- if column.name.end_with?("_id") && (reflection = admin.model.reflections[column.name.sub(/_id$/, '')])
56
- Attribute::Association.new(admin, column.name, reflection.klass)
62
+ model.columns.map do |column|
63
+ if column.name.end_with?("_id") && (name = column.name.sub(/_id$/, '')) && (reflection = model.reflections[name])
64
+ Attribute::Association.new(column.name, class: -> { reflection.klass }, name: name, polymorphic: reflection.polymorphic?, type_column: reflection.foreign_type)
65
+ elsif column.name.end_with?("_type") && (name = column.name.sub(/_type$/, '')) && (reflection = model.reflections[name])
66
+ # Ignore type columns for polymorphic associations
57
67
  else
58
- Attribute.new(admin, column.name, column.type)
68
+ Attribute.new(column.name, column.type, array_column?(column) ? { array: true } : {})
59
69
  end
60
- end
70
+ end.compact
71
+ end
72
+
73
+ def primary_key?(attribute)
74
+ attribute.name.to_s == model.primary_key
75
+ end
76
+
77
+ def inheritance_column?(attribute)
78
+ attribute.name.to_s == model.inheritance_column
79
+ end
80
+
81
+ def counter_cache_column?(attribute)
82
+ attribute.name.to_s.end_with?("_count")
83
+ end
84
+
85
+ def array_column?(column)
86
+ column.respond_to?(:array?) && column.array?
61
87
  end
62
88
  end
63
89
  end
@@ -0,0 +1,176 @@
1
+ module Trestle
2
+ module Adapters
3
+ class Adapter
4
+ attr_reader :admin
5
+ delegate :model, to: :admin
6
+
7
+ def initialize(admin)
8
+ @admin = admin
9
+ end
10
+
11
+ # Loads the initial collection for use by the index action.
12
+ #
13
+ # params - Unfiltered params hash from the controller
14
+ #
15
+ # Returns a scope object that can be chained with other methods (e.g. sort, paginate, count, etc).
16
+ def collection(params={})
17
+ raise NotImplementedError
18
+ end
19
+
20
+ # Finds (and returns) an individual instance for use by the show, edit, update, destroy actions.
21
+ #
22
+ # params - Unfiltered params hash from the controller
23
+ def find_instance(params)
24
+ raise NotImplementedError
25
+ end
26
+
27
+ # Builds (and returns) a new instance for new/create actions.
28
+ #
29
+ # attrs - Permitted attributes to set on the new instance
30
+ # params - Unfiltered params hash from the controller
31
+ def build_instance(attrs={}, params={})
32
+ raise NotImplementedError
33
+ end
34
+
35
+ # Updates (but does not save) a given resource's attributes.
36
+ #
37
+ # instance - The instance to update
38
+ # attrs - Permitted attributes to update on the instance
39
+ # params - Unfiltered params hash from the controller
40
+ #
41
+ # The return value is ignored.
42
+ def update_instance(instance, attrs, params={})
43
+ raise NotImplementedError
44
+ end
45
+
46
+ # Saves an instance (used by the create and update actions).
47
+ #
48
+ # instance - The instance to save
49
+ #
50
+ # Returns a boolean indicating the success/fail status of the save.
51
+ def save_instance(instance)
52
+ raise NotImplementedError
53
+ end
54
+
55
+ # Deletes an instance (used by the destroy action).
56
+ #
57
+ # instance - The instance to delete
58
+ #
59
+ # Returns a boolean indicating the success/fail status of the deletion.
60
+ def delete_instance(instance)
61
+ raise NotImplementedError
62
+ end
63
+
64
+ # Decorates a collection for rendering by the index view.
65
+ # Decorating is the final step in preparing the collection for the view.
66
+ #
67
+ # collection - The collection to decorate
68
+ #
69
+ # Returns an enumerable collection of instances.
70
+ def decorate_collection(collection)
71
+ collection
72
+ end
73
+
74
+ # Converts an instance to a URL parameter. The result of this method is passed to the #find_instance
75
+ # adapter method as params[:id]. It is recommended to simply use the instance's #id, as other potential options
76
+ # such as a permalink/slug could potentially be changed during editing.
77
+ #
78
+ # instance - The instance to convert
79
+ #
80
+ # Returns the URL representation of the instance.
81
+ def to_param(instance)
82
+ instance.id
83
+ end
84
+
85
+ # Unscopes a collection so that it can be merged with other scopes without duplication or interference.
86
+ #
87
+ # scope - The scope to unscope
88
+ #
89
+ # Returns a scope object.
90
+ def unscope(scope)
91
+ scope
92
+ end
93
+
94
+ # Merges scopes together for Trestle scope application and counting.
95
+ #
96
+ # scope - The first scope
97
+ # other - The second scope
98
+ #
99
+ # Returns a scope object representing the combination of the two given scopes.
100
+ def merge_scopes(scope, other)
101
+ raise NotImplementedError
102
+ end
103
+
104
+ # Counts the number of objects in a collection for use by scope links.
105
+ #
106
+ # collection - The collection to count
107
+ #
108
+ # Returns the total number (integer) of objects in the collection.
109
+ def count(collection)
110
+ raise NotImplementedError
111
+ end
112
+
113
+ # Sorts the collection by the given field and order.
114
+ # This method is called when an explicit sort column for the given field is not defined.
115
+ #
116
+ # collection - The collection to sort
117
+ # field - The field to sort by
118
+ # order - Symbol (:asc or :desc) representing the sort order (ascending or descending)
119
+ #
120
+ # Returns a scope object
121
+ def sort(collection, field, order)
122
+ raise NotImplementedError
123
+ end
124
+
125
+ # Paginates a collection for use by the index action.
126
+ #
127
+ # collection - The collection to paginate
128
+ # params - Unfiltered params hash from the controller:
129
+ # :page - current page number
130
+ #
131
+ # Returns a Kaminari-compatible scope corresponding to a single page.
132
+ def paginate(collection, params)
133
+ collection = Kaminari.paginate_array(collection.to_a) unless collection.respond_to?(:page)
134
+ collection.page(params[:page])
135
+ end
136
+
137
+ # Filters the submitted form parameters and returns a whitelisted attributes 'hash'
138
+ # that can be set or updated on a model instance.
139
+ #
140
+ # IMPORTANT: By default, all params are permitted, which assumes a trusted administrator. If this is not the
141
+ # case, a `params` block should be individually declared for each admin with the set of permitted parameters.
142
+ #
143
+ # params - Unfiltered params hash from the controller
144
+ #
145
+ # Returns the permitted set of parameters as a ActionController::Parameters object.
146
+ def permitted_params(params)
147
+ params.require(admin.admin_name.singularize).permit!
148
+ end
149
+
150
+ # Produces a human-readable name for a given attribute, applying I18n where appropriate.
151
+ # See ActiveModel::Translation for an implementation of this method.
152
+ #
153
+ # attribute - Attribute name (Symbol)
154
+ # options - Hash of options [not currently used]
155
+ #
156
+ # Returns the human-readable name of the given attribute as a String.
157
+ def human_attribute_name(attribute, options={})
158
+ attribute.to_s.titleize
159
+ end
160
+
161
+ # Generates a list of attributes that should be rendered by the index (table) view.
162
+ #
163
+ # Returns an Array of Trestle::Attribute and/or Trestle::Attribute::Association objects.
164
+ def default_table_attributes
165
+ raise NotImplementedError
166
+ end
167
+
168
+ # Generates a list of attributes that should be rendered by the new/show/edit (form) views.
169
+ #
170
+ # Returns an Array of Trestle::Attribute and/or Trestle::Attribute::Association objects.
171
+ def default_form_attributes
172
+ raise NotImplementedError
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,85 @@
1
+ begin
2
+ require "sequel"
3
+ rescue LoadError
4
+ $stderr.puts "You don't have sequel installed in your application. Please add it to your Gemfile and run bundle install"
5
+ raise
6
+ end
7
+
8
+ Sequel::Model.plugin :active_model
9
+
10
+ module Trestle
11
+ module Adapters
12
+ module SequelAdapter
13
+ def collection(params={})
14
+ model.dataset
15
+ end
16
+
17
+ def find_instance(params)
18
+ model[params[:id]]
19
+ end
20
+
21
+ def build_instance(attrs={}, params={})
22
+ model.new(attrs)
23
+ end
24
+
25
+ def update_instance(instance, attrs, params={})
26
+ instance.set(attrs)
27
+ end
28
+
29
+ def save_instance(instance)
30
+ instance.save
31
+ end
32
+
33
+ def delete_instance(instance)
34
+ instance.destroy
35
+ end
36
+
37
+ def unscope(scope)
38
+ scope.unfiltered
39
+ end
40
+
41
+ def merge_scopes(scope, other)
42
+ scope.intersect(other)
43
+ end
44
+
45
+ def count(collection)
46
+ collection.count
47
+ end
48
+
49
+ def sort(collection, field, order)
50
+ collection.order(Sequel.send(order, field))
51
+ end
52
+
53
+ def default_table_attributes
54
+ default_attributes.reject do |attribute|
55
+ inheritance_column?(attribute)
56
+ end
57
+ end
58
+
59
+ def default_form_attributes
60
+ default_attributes.reject do |attribute|
61
+ primary_key?(attribute) || inheritance_column?(attribute)
62
+ end
63
+ end
64
+
65
+ protected
66
+ def default_attributes
67
+ model.db_schema.map do |column_name, column_attrs|
68
+ if column_name.to_s.end_with?("_id") && (name = column_name.to_s.sub(/_id$/, '')) && (reflection = model.association_reflection(name.to_sym))
69
+ Attribute::Association.new(column_name, class: -> { reflection.associated_class }, name: name)
70
+ else
71
+ Attribute.new(column_name, column_attrs[:type])
72
+ end
73
+ end
74
+ end
75
+
76
+ def primary_key?(attribute)
77
+ attribute.name.to_s == model.primary_key.to_s
78
+ end
79
+
80
+ def inheritance_column?(attribute)
81
+ model.respond_to?(:sti_key) && attribute.name.to_s == model.sti_key.to_s
82
+ end
83
+ end
84
+ end
85
+ end