simple-admin 0.1.0.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +3 -0
  3. data/.gitattributes +1 -0
  4. data/.gitignore +17 -0
  5. data/.hound.yml +2 -0
  6. data/.inch.yml +4 -0
  7. data/.rspec +2 -0
  8. data/.rubocop.yml +68 -0
  9. data/.travis.yml +11 -0
  10. data/CODE_OF_CONDUCT.md +74 -0
  11. data/CONTRIBUTING.md +51 -0
  12. data/Gemfile +27 -0
  13. data/LICENSE.txt +21 -0
  14. data/README.md +87 -0
  15. data/Rakefile +20 -0
  16. data/app/assets/fonts/Simple-Line-Icons.woff +0 -0
  17. data/app/assets/javascripts/simple_admin/application.js +28 -0
  18. data/app/assets/stylesheets/simple_admin/application.scss +48 -0
  19. data/app/assets/stylesheets/simple_admin/global/buttons.css +473 -0
  20. data/app/assets/stylesheets/simple_admin/global/errors.css +12 -0
  21. data/app/assets/stylesheets/simple_admin/global/fontawesome-icons.css +3024 -0
  22. data/app/assets/stylesheets/simple_admin/global/fonts.css +560 -0
  23. data/app/assets/stylesheets/simple_admin/global/jquery.dataTables.css +169 -0
  24. data/app/assets/stylesheets/simple_admin/global/pagination.css +11 -0
  25. data/app/assets/stylesheets/simple_admin/global/reset.css +197 -0
  26. data/app/assets/stylesheets/simple_admin/global/simple-line-icons.css +672 -0
  27. data/app/assets/stylesheets/simple_admin/global/table.css +214 -0
  28. data/app/assets/stylesheets/simple_admin/global/tags.css +87 -0
  29. data/app/assets/stylesheets/simple_admin/page/aside.css +324 -0
  30. data/app/assets/stylesheets/simple_admin/page/header.css +332 -0
  31. data/app/assets/stylesheets/simple_admin/page/main-container.css +222 -0
  32. data/app/assets/stylesheets/simple_admin/page/sign_in.css +15 -0
  33. data/app/assets/stylesheets/simple_admin/tabs.css +26 -0
  34. data/app/controllers/simple_admin/admin/application_controller.rb +21 -0
  35. data/app/controllers/simple_admin/admin/search_controller.rb +29 -0
  36. data/app/controllers/simple_admin/admin/system/entities_controller.rb +37 -0
  37. data/app/controllers/simple_admin/admin/system/entity_field_types_controller.rb +31 -0
  38. data/app/controllers/simple_admin/admin/system/entity_fields_controller.rb +20 -0
  39. data/app/helpers/simple_admin_helper.rb +15 -0
  40. data/app/models/simple_admin/base.rb +14 -0
  41. data/app/models/simple_admin/entity.rb +50 -0
  42. data/app/models/simple_admin/entity_field.rb +77 -0
  43. data/app/models/simple_admin/entity_field_setting.rb +5 -0
  44. data/app/models/simple_admin/entity_field_type.rb +79 -0
  45. data/app/views/kaminari/_next_page.html.erb +5 -0
  46. data/app/views/kaminari/_page.html.erb +3 -0
  47. data/app/views/kaminari/_paginator.html.erb +26 -0
  48. data/app/views/kaminari/_prev_page.html.erb +5 -0
  49. data/app/views/layouts/devise.html.erb +11 -0
  50. data/app/views/layouts/simple_admin.html.erb +28 -0
  51. data/app/views/simple_admin/admin/resource/_form.html.erb +19 -0
  52. data/app/views/simple_admin/admin/resource/edit.html.erb +21 -0
  53. data/app/views/simple_admin/admin/resource/index.html.erb +13 -0
  54. data/app/views/simple_admin/admin/resource/new.html.erb +21 -0
  55. data/app/views/simple_admin/admin/search/index.html.erb +55 -0
  56. data/app/views/simple_admin/admin/shared/_aside.html.erb +46 -0
  57. data/app/views/simple_admin/admin/shared/_footer.html.erb +5 -0
  58. data/app/views/simple_admin/admin/shared/_header.html.erb +7 -0
  59. data/app/views/simple_admin/admin/shared/collection/_header.html.erb +12 -0
  60. data/app/views/simple_admin/admin/shared/collection/_table_body.html.erb +29 -0
  61. data/app/views/simple_admin/admin/shared/collection/_table_header.html.erb +11 -0
  62. data/app/views/simple_admin/admin/shared/components/_logout.html.erb +6 -0
  63. data/app/views/simple_admin/admin/shared/components/_search.html.erb +14 -0
  64. data/app/views/simple_admin/admin/shared/messages/_errors.html.erb +9 -0
  65. data/app/views/simple_admin/admin/shared/messages/_flash.html.erb +8 -0
  66. data/app/views/simple_admin/admin/system/entities/_form.html.erb +32 -0
  67. data/app/views/simple_admin/admin/system/entities/edit.html.erb +27 -0
  68. data/app/views/simple_admin/admin/system/entities/entity_fields/_form.html.erb +62 -0
  69. data/app/views/simple_admin/admin/system/entities/entity_fields/edit.html.erb +9 -0
  70. data/app/views/simple_admin/admin/system/entities/entity_fields/index.html.erb +39 -0
  71. data/app/views/simple_admin/admin/system/entities/entity_fields/new.html.erb +12 -0
  72. data/app/views/simple_admin/admin/system/entities/index.html.erb +59 -0
  73. data/app/views/simple_admin/admin/system/entities/new.html.erb +21 -0
  74. data/app/views/simple_admin/admin/system/entity_field_types/_form.html.erb +21 -0
  75. data/app/views/simple_admin/admin/system/entity_field_types/edit.html.erb +24 -0
  76. data/app/views/simple_admin/admin/system/entity_field_types/index.html.erb +55 -0
  77. data/app/views/simple_admin/admin/system/entity_field_types/new.html.erb +21 -0
  78. data/app/views/simple_admin/admin/system/entity_fields/create.js.erb +18 -0
  79. data/app/views/simple_admin/admin/system/entity_fields/destroy.js.erb +18 -0
  80. data/app/views/simple_admin/admin/system/entity_fields/update.js.erb +1 -0
  81. data/app/views/simple_admin/fields/boolean/_form.html.erb +6 -0
  82. data/app/views/simple_admin/fields/boolean/_index.html.erb +5 -0
  83. data/app/views/simple_admin/fields/image/_collection.html.erb +5 -0
  84. data/app/views/simple_admin/fields/image/_form.html.erb +6 -0
  85. data/app/views/simple_admin/fields/number/_collection.html.erb +5 -0
  86. data/app/views/simple_admin/fields/number/_form.html.erb +6 -0
  87. data/app/views/simple_admin/fields/password/_form.html.erb +6 -0
  88. data/app/views/simple_admin/fields/relation/_collection.html.erb +3 -0
  89. data/app/views/simple_admin/fields/relation/_form.html.erb +6 -0
  90. data/app/views/simple_admin/fields/select/_form.html.erb +8 -0
  91. data/app/views/simple_admin/fields/select/_index.html.erb +5 -0
  92. data/app/views/simple_admin/fields/string/_collection.html.erb +3 -0
  93. data/app/views/simple_admin/fields/string/_form.html.erb +6 -0
  94. data/app/views/simple_admin/fields/tags/_collection.html.erb +3 -0
  95. data/app/views/simple_admin/fields/tags/_form.html.erb +6 -0
  96. data/app/views/simple_admin/fields/text/_collection.html.erb +3 -0
  97. data/app/views/simple_admin/fields/text/_form.html.erb +6 -0
  98. data/bin/bundle +4 -0
  99. data/bin/rails +5 -0
  100. data/codecov.yml +21 -0
  101. data/config/locales/en.yml +23 -0
  102. data/config/locales/ru.yml +20 -0
  103. data/config/routes.rb +19 -0
  104. data/lib/generators/simple_admin/install_generator.rb +41 -0
  105. data/lib/generators/simple_admin/migration_generator.rb +24 -0
  106. data/lib/generators/templates/application_controller.rb +20 -0
  107. data/lib/generators/templates/initializers/simple_admin.rb.erb +3 -0
  108. data/lib/generators/templates/migrations/core_data_migration.rb +12 -0
  109. data/lib/generators/templates/migrations/core_migrations/entities_migration.rb +13 -0
  110. data/lib/generators/templates/migrations/core_migrations/entity_field_settings_migration.rb +12 -0
  111. data/lib/generators/templates/migrations/core_migrations/entity_field_types_migration.rb +12 -0
  112. data/lib/generators/templates/migrations/core_migrations/entity_fields_migration.rb +18 -0
  113. data/lib/generators/templates/user.rb +24 -0
  114. data/lib/generators/templates/views/devise/registrations/new.html.erb +46 -0
  115. data/lib/generators/templates/views/devise/sessions/new.html.erb +35 -0
  116. data/lib/generators/templates/views/devise/shared/_footer.html.erb +3 -0
  117. data/lib/simple_admin.rb +39 -0
  118. data/lib/simple_admin/config.rb +19 -0
  119. data/lib/simple_admin/engine.rb +15 -0
  120. data/lib/simple_admin/helpers/boolean_helper.rb +36 -0
  121. data/lib/simple_admin/helpers/url_helper.rb +29 -0
  122. data/lib/simple_admin/refinements/boolean.rb +36 -0
  123. data/lib/simple_admin/resource_controller/actions_builder.rb +40 -0
  124. data/lib/simple_admin/resource_controller/controller_builder.rb +31 -0
  125. data/lib/simple_admin/resource_controller/crudify.rb +111 -0
  126. data/lib/simple_admin/resource_controller/crudify_dynamic_resource.rb +55 -0
  127. data/lib/simple_admin/resource_controller/dynamic_fields.rb +53 -0
  128. data/lib/simple_admin/search.rb +23 -0
  129. data/lib/simple_admin/version.rb +3 -0
  130. data/simple_admin.gemspec +38 -0
  131. data/vendor/assets/fonts/Simple-Line-Icons.eot +0 -0
  132. data/vendor/assets/fonts/Simple-Line-Icons.ttf +0 -0
  133. data/vendor/assets/fonts/Simple-Line-Icons.woff +0 -0
  134. data/vendor/assets/fonts/fontawesome-webfont.eot +0 -0
  135. data/vendor/assets/fonts/fontawesome-webfont.svg +2671 -0
  136. data/vendor/assets/fonts/fontawesome-webfont.ttf +0 -0
  137. data/vendor/assets/fonts/fontawesome-webfont.woff +0 -0
  138. data/vendor/assets/fonts/fontawesome-webfont.woff2 +0 -0
  139. metadata +307 -0
@@ -0,0 +1,15 @@
1
+ .content.content-boxed {
2
+ max-width: 1280px;
3
+ }
4
+
5
+ .pulldown {
6
+ position: relative;
7
+ top: 50px;
8
+ }
9
+
10
+ @media screen and (min-width: 992px) {
11
+ /* line 9052, /Users/dmitriy/Projects/exampleapp/gemfiles/simple_admin/app/assets/stylesheets/simple_admin/core.scss */
12
+ .pulldown {
13
+ top: 150px;
14
+ }
15
+ }
@@ -0,0 +1,26 @@
1
+ .block > .nav-tabs {
2
+ background-color: #f9f9f9;
3
+ border-bottom: none;
4
+ }
5
+
6
+ .block > .nav-tabs > li.ui-tabs-active > a, .block > .nav-tabs > li.ui-tabs-active > a:hover, .block > .nav-tabs > li.ui-tabs-active > a:focus {
7
+ color: #646464;
8
+ background-color: #fff;
9
+ border-color: transparent;
10
+ }
11
+
12
+ .block > .nav-tabs > li > a {
13
+ margin-right: 0;
14
+ padding-top: 12px;
15
+ padding-bottom: 12px;
16
+ color: #646464;
17
+ font-weight: 600;
18
+ border: 1px solid transparent;
19
+ border-radius: 0;
20
+ }
21
+
22
+ .nav {
23
+ margin-bottom: 0!important;
24
+ padding-left: 0!important;
25
+ list-style: none;
26
+ }
@@ -0,0 +1,21 @@
1
+ module SimpleAdmin
2
+ module Admin
3
+ class ApplicationController < ActionController::Base
4
+ layout 'simple_admin'
5
+
6
+ before_action :authenticate_user!
7
+
8
+ def current_user
9
+ # TODO: Add authenticated user here
10
+ raise NotImplementedError
11
+ end
12
+
13
+ private
14
+
15
+ def authenticate_user!
16
+ # TODO: Add authentication logic here
17
+ raise NotImplementedError
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ module SimpleAdmin
2
+ module Admin
3
+ class SearchController < SimpleAdmin::Admin::ApplicationController
4
+ PER_PAGE = 10
5
+
6
+ before_action :initialize_fields_entities!
7
+
8
+ def index
9
+ @resources = SimpleAdmin::Search.new(params[:query], params[:resource_klass].constantize).process
10
+ @resources = @resources.page(params[:page]).per(PER_PAGE) if @resources.present?
11
+
12
+ @resource_name = @entity.model_klass.model_name.element.capitalize
13
+ end
14
+
15
+ def initialize_fields_entities!
16
+ raise ActiveRecord::RecordNotFound if search_params_blank?
17
+
18
+ @entity = SimpleAdmin::Entity.find_by(model_klass_name: params[:resource_klass])
19
+ @entity_fields = @entity.entity_fields.collection
20
+ end
21
+
22
+ private
23
+
24
+ def search_params_blank?
25
+ params[:resource_klass].blank? || params[:query].blank?
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,37 @@
1
+ module SimpleAdmin
2
+ module Admin
3
+ module System
4
+ class EntitiesController < SimpleAdmin::Admin::ApplicationController
5
+ include ResourceController::Crudify
6
+
7
+ before_action :reload_models!, only: %i[new edit]
8
+
9
+ def model_klass
10
+ SimpleAdmin::Entity
11
+ end
12
+
13
+ def after_create_path
14
+ edit_admin_system_entity_path(@resource)
15
+ end
16
+
17
+ def after_update_path
18
+ admin_system_entities_path
19
+ end
20
+
21
+ def after_destroy_path
22
+ admin_system_entities_path
23
+ end
24
+
25
+ private
26
+
27
+ def resource_params
28
+ params.require(:simple_admin_entity).permit(:model_klass_name, :label, :status)
29
+ end
30
+
31
+ def reload_models!
32
+ Rails.application.eager_load!
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,31 @@
1
+ module SimpleAdmin
2
+ module Admin
3
+ module System
4
+ class EntityFieldTypesController < SimpleAdmin::Admin::ApplicationController
5
+ include ResourceController::Crudify
6
+
7
+ def model_klass
8
+ SimpleAdmin::EntityFieldType
9
+ end
10
+
11
+ def after_create_path
12
+ admin_system_entity_field_types_path
13
+ end
14
+
15
+ def after_update_path
16
+ admin_system_entity_field_types_path
17
+ end
18
+
19
+ def after_destroy_path
20
+ admin_system_entity_field_types_path
21
+ end
22
+
23
+ private
24
+
25
+ def resource_params
26
+ params.require(:simple_admin_entity_field_type).permit(:name, :template)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ module SimpleAdmin
2
+ module Admin
3
+ module System
4
+ class EntityFieldsController < SimpleAdmin::Admin::ApplicationController
5
+ include ResourceController::CrudifyDynamicResource
6
+
7
+ def model_klass
8
+ SimpleAdmin::EntityField
9
+ end
10
+
11
+ private
12
+
13
+ def resource_params
14
+ params.require(:simple_admin_entity_field).permit(:name, :label, :entity_field_type_id, :entity_id, :presentation,
15
+ :search_indexable, entity_field_setting_attributes: [:value])
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ module SimpleAdminHelper
2
+ include SimpleAdmin::Helpers::UrlHelper
3
+
4
+ def resources_pagination_start(per_page, current_page)
5
+ (per_page * current_page.to_i) - (per_page - 1)
6
+ end
7
+
8
+ def resources_pagination_end(per_page, current_page)
9
+ (per_page * current_page.to_i) + 1
10
+ end
11
+
12
+ def resource_index_path(resource_name, prefix=:admin_system, postfix=:path)
13
+ public_send("#{prefix}_#{resource_name}_#{postfix}")
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ module SimpleAdmin
2
+ class Base < ApplicationRecord
3
+ self.abstract_class = true
4
+ self.table_name_prefix = 'simple_admin_'
5
+
6
+ class << self
7
+ def custom_model_names(namespace='SimpleAdmin')
8
+ ApplicationRecord.descendants.map do |model|
9
+ [model.name, model.name] unless model.name.include?(namespace)
10
+ end.compact
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,50 @@
1
+ module SimpleAdmin
2
+ class Entity < Base
3
+ include Helpers::BooleanHelper
4
+
5
+ boolean_fields :status
6
+
7
+ has_many :entity_fields
8
+
9
+ scope :enabled, -> { where(status: true) }
10
+
11
+ validates :model_klass_name, presence: true
12
+
13
+ before_save :label_default_value!
14
+ after_create :create_default_fields!
15
+
16
+ after_save :reload_routes! unless Rails.env.test?
17
+
18
+ class << self
19
+ def form_attributes(model_klass)
20
+ find_by(model_klass_name: model_klass.to_s).entity_fields.form.pluck(:name)
21
+ end
22
+
23
+ def resource_attributes
24
+ enabled.map do |entity|
25
+ [entity.model_klass.model_name.collection, entity.model_klass_name]
26
+ end
27
+ end
28
+ end
29
+
30
+ def model_klass
31
+ model_klass_name.constantize
32
+ end
33
+
34
+ private
35
+
36
+ def reload_routes!
37
+ Rails.application.routes_reloader.reload!
38
+ end
39
+
40
+ def label_default_value!
41
+ return if label.present?
42
+ self.label = model_klass.model_name.human.pluralize
43
+ end
44
+
45
+ def create_default_fields!
46
+ SimpleAdmin::EntityFieldType.reload_helper_methods!
47
+ SimpleAdmin::EntityField.create_number_field(name: :id, label: '#', entity: self, presentation: :collection)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,77 @@
1
+ module SimpleAdmin
2
+ class EntityField < Base
3
+ enum presentation: %i[collection form]
4
+
5
+ belongs_to :entity
6
+
7
+ has_one :entity_field_type, primary_key: :entity_field_type_id, foreign_key: :id
8
+ has_one :entity_field_setting, dependent: :destroy
9
+
10
+ accepts_nested_attributes_for :entity_field_setting, update_only: true
11
+ delegate :value, to: :entity_field_setting, allow_nil: true
12
+
13
+ validate :name_presentation_uniqueness, on: :create
14
+
15
+ scope :latest, -> { order(created_at: :asc) }
16
+ scope :labels, -> { latest.pluck(:label) }
17
+
18
+ scope :search_indexable_columns, -> { collection.where(search_indexable: true).pluck(:name) }
19
+
20
+ before_save :label_default_value!
21
+
22
+ def id_field?
23
+ name == 'id'
24
+ end
25
+
26
+ # Entity association class for field
27
+ # @example SimpleAdmin::Post
28
+ # module SimpleAdmin
29
+ # class Post < Base
30
+ # belongs_to :category, optional: true
31
+ # end
32
+ # end
33
+ #
34
+ # entity = SimpleAdmin::Entity.create(model_klass_name: SimpleAdmin::Post.to_s)
35
+ # entity_field_type = SimpleAdmin::EntityFieldType.create(name: :relation, template: 'simple_admin/fields/relation')
36
+ #
37
+ # entity_field = SimpleAdmin::EntityField.new(name: :category_id, label: 'Category',
38
+ # entity_field_type: entity_field_type, entity: entity)
39
+ # entity_field.association_klass
40
+ #
41
+ # SimpleAdmin::Category
42
+ #
43
+ # @return [ActiveRecord Class]
44
+ #
45
+ # @since 0.1.0
46
+ def association_klass
47
+ model_instance = entity.model_klass.new
48
+ association_name = name.remove('_id')
49
+
50
+ model_instance.public_send("build_#{association_name}").class
51
+ end
52
+
53
+ # Template path for field
54
+ #
55
+ # @return [String]
56
+ #
57
+ # @since 0.1.0
58
+ def template_path
59
+ "#{entity_field_type.template}/#{presentation}"
60
+ end
61
+
62
+ def already_exists?
63
+ self.class.where(name: name, presentation: presentation, entity: entity).any?
64
+ end
65
+
66
+ private
67
+
68
+ def label_default_value!
69
+ return if id_field? || label.present?
70
+ self.label = name.camelize
71
+ end
72
+
73
+ def name_presentation_uniqueness
74
+ errors.add(:name, 'already exists') if already_exists?
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,5 @@
1
+ module SimpleAdmin
2
+ class EntityFieldSetting < Base
3
+ belongs_to :entity_field
4
+ end
5
+ end
@@ -0,0 +1,79 @@
1
+ module SimpleAdmin
2
+ class EntityFieldType < Base
3
+ include Helpers::BooleanHelper
4
+
5
+ boolean_fields :inbuilt
6
+
7
+ belongs_to :entity_field, optional: true
8
+
9
+ validate :view_templates_presence, unless: :inbuilt?
10
+
11
+ after_create :initialize_helper_methods!
12
+
13
+ class << self
14
+ # Define entity fields model methods to simplify creation.
15
+ # You not need to define entity_field_type directly
16
+ # Use:
17
+ # SimpleAdmin::EntityField.create_string_field(name: :title, entity: entity, presentation: :collection)
18
+ # SimpleAdmin::EntityField.create_number_field(name: :id, entity: entity, presentation: :collection)
19
+ #
20
+ # @since 0.1.0
21
+ def build_helper_methods!
22
+ pluck(:name).each do |field_type_name|
23
+ SimpleAdmin::EntityField.define_singleton_method("create_#{field_type_name}_field") do |params|
24
+ params[:entity_field_type_id] = SimpleAdmin::EntityFieldType.find_by(name: field_type_name).to_param
25
+
26
+ create(params)
27
+ end
28
+ end
29
+ end
30
+
31
+ def reload_helper_methods!
32
+ build_helper_methods!
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def initialize_helper_methods!
39
+ self.class.build_helper_methods!
40
+ end
41
+
42
+ def view_templates_presence
43
+ validate_collection_template!
44
+ validate_form_template!
45
+ end
46
+
47
+ def validate_collection_template!
48
+ collection_template_path =
49
+ if Rails.env.test?
50
+ "spec/example_app/app/views/#{template}/_collection.*"
51
+ else
52
+ "app/views/#{template}/_collection.*"
53
+ end
54
+
55
+ unless template_exists?(collection_template_path)
56
+ errors.add(:base, 'Collection template missing')
57
+ end
58
+ end
59
+
60
+ def validate_form_template!
61
+ form_template_path =
62
+ if Rails.env.test?
63
+ "spec/example_app/app/views/#{template}/_form.*"
64
+ else
65
+ "app/views/#{template}/_form.*"
66
+ end
67
+
68
+ errors.add(:base, 'Form template missing') unless template_exists?(form_template_path)
69
+ end
70
+
71
+ def template_exists?(template_path)
72
+ !Dir.glob(template_path).empty? || !Dir.glob("#{core_path}/#{template_path}").empty?
73
+ end
74
+
75
+ def core_path
76
+ Gem.loaded_specs['simple_admin'].full_gem_path
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,5 @@
1
+ <li class="paginate_button next <%= 'disabled' if current_page.last? %>" aria-controls="DataTables_Table_1" tabindex="0" id="DataTables_Table_1_next">
2
+ <%= link_to url, remote: remote do %>
3
+ <i class="fa fa-angle-right"></i>
4
+ <% end %>
5
+ </li>
@@ -0,0 +1,3 @@
1
+ <li class="paginate_button <%= 'active' if page.current? %>" aria-controls="DataTables_Table_1" tabindex="0">
2
+ <%= link_to page, url, { remote: remote, rel: page.rel } %>
3
+ </li>