adminable 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +49 -62
  3. data/app/controllers/adminable/resources_controller.rb +19 -28
  4. data/app/views/adminable/resources/_form.html.haml +2 -2
  5. data/app/views/adminable/resources/_search.html.haml +3 -3
  6. data/app/views/adminable/resources/form/_belongs_to.html.haml +5 -5
  7. data/app/views/adminable/resources/form/_boolean.html.haml +4 -4
  8. data/app/views/adminable/resources/form/_date.html.haml +3 -3
  9. data/app/views/adminable/resources/form/_datetime.html.haml +3 -3
  10. data/app/views/adminable/resources/form/_decimal.html.haml +3 -3
  11. data/app/views/adminable/resources/form/_float.html.haml +3 -3
  12. data/app/views/adminable/resources/form/_has_many.html.haml +5 -5
  13. data/app/views/adminable/resources/form/_integer.html.haml +3 -3
  14. data/app/views/adminable/resources/form/_string.html.haml +3 -3
  15. data/app/views/adminable/resources/form/_text.html.haml +4 -4
  16. data/app/views/adminable/resources/form/_time.html.haml +3 -3
  17. data/app/views/adminable/resources/form/_timestamp.html.haml +3 -3
  18. data/app/views/adminable/resources/index.html.haml +10 -10
  19. data/app/views/adminable/shared/_label.html.haml +4 -4
  20. data/lib/adminable.rb +15 -16
  21. data/lib/adminable/errors.rb +5 -2
  22. data/lib/adminable/field_collector.rb +53 -0
  23. data/lib/adminable/{attributes → fields}/base.rb +21 -13
  24. data/lib/adminable/fields/belongs_to.rb +9 -0
  25. data/lib/adminable/fields/boolean.rb +6 -0
  26. data/lib/adminable/fields/date.rb +6 -0
  27. data/lib/adminable/fields/datetime.rb +6 -0
  28. data/lib/adminable/fields/decimal.rb +6 -0
  29. data/lib/adminable/fields/float.rb +6 -0
  30. data/lib/adminable/fields/has_many.rb +13 -0
  31. data/lib/adminable/fields/integer.rb +6 -0
  32. data/lib/adminable/fields/string.rb +6 -0
  33. data/lib/adminable/fields/text.rb +6 -0
  34. data/lib/adminable/fields/time.rb +6 -0
  35. data/lib/adminable/fields/timestamp.rb +6 -0
  36. data/lib/adminable/presenters/fields.rb +17 -0
  37. data/lib/adminable/resource.rb +5 -17
  38. data/lib/adminable/version.rb +1 -1
  39. data/lib/generators/adminable/resource/templates/resource_controller.rb.erb +6 -1
  40. data/lib/generators/adminable/resource_generator.rb +9 -1
  41. metadata +17 -17
  42. data/lib/adminable/attributes/association.rb +0 -14
  43. data/lib/adminable/attributes/collection.rb +0 -116
  44. data/lib/adminable/attributes/types/belongs_to.rb +0 -11
  45. data/lib/adminable/attributes/types/boolean.rb +0 -8
  46. data/lib/adminable/attributes/types/date.rb +0 -8
  47. data/lib/adminable/attributes/types/datetime.rb +0 -8
  48. data/lib/adminable/attributes/types/decimal.rb +0 -8
  49. data/lib/adminable/attributes/types/float.rb +0 -8
  50. data/lib/adminable/attributes/types/has_many.rb +0 -15
  51. data/lib/adminable/attributes/types/integer.rb +0 -8
  52. data/lib/adminable/attributes/types/string.rb +0 -8
  53. data/lib/adminable/attributes/types/text.rb +0 -8
  54. data/lib/adminable/attributes/types/time.rb +0 -8
  55. data/lib/adminable/attributes/types/timestamp.rb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 50dbc10813e44d6cbaafaf677198e95604541bd9
4
- data.tar.gz: 1a583fe099f1a41a986ff8e61b2deb632dae6e9e
3
+ metadata.gz: 6ddb7fa61bee7a687cdc0c39c37990d5bb521304
4
+ data.tar.gz: 39e26845450a55d099ed58a2abc9feb49c151427
5
5
  SHA512:
6
- metadata.gz: 1f46365f19a81adde1666e349976db7626b32a396db05ef6546e9e1a2681816ec4b66c7c02e782a4e8d687ffec705c873550311eb3efbf96cd76dec9fff1af2b
7
- data.tar.gz: e735b3c8245ba04e89450b6bf444d9e628eeaa816498875a91fb3d0a6e3918431cc3993f8b6b08b531595b1a3ebb8316af1e022b15204fd2e061d2ccfe2feeeb
6
+ metadata.gz: 030afe5a4016c70a0ecbd93ab4d42872b2b14307f697d2268f36707c400b8cd0d6a28a93baa939dd4de0ce0cf6b2d89260de5ae618089fc5ee97c0b6fd32d85e
7
+ data.tar.gz: be70b417ed4ef1804fd51549fda2443645be24f6cf3463cb9ffbbdafe3df0eef12dc951ec4c0597ce56592b86e439fec6e64c2c06b2d4c0543020b6f2d66f948
data/README.md CHANGED
@@ -11,7 +11,7 @@ Simple admin interface for Ruby on Rails applications.
11
11
 
12
12
  ## Features
13
13
 
14
- * Built with common Rails controllers with a small DSL.
14
+ * Built with common Rails controllers and views without DSL.
15
15
  * Supports namespaced models.
16
16
  * Has simple search with [Ransack](https://github.com/activerecord-hackery/ransack).
17
17
  * Uses [Bootstrap](https://github.com/twbs/bootstrap) 4.0.
@@ -43,7 +43,7 @@ $ gem install adminable
43
43
 
44
44
  ## Getting Started
45
45
 
46
- First things first. Add routes and create `application_controller.rb` class using generator:
46
+ First things first. Add routes and create `adminable/application_controller.rb` class using generator:
47
47
 
48
48
  ```bash
49
49
  rails g adminable:install
@@ -51,93 +51,80 @@ rails g adminable:install
51
51
  # => insert config/routes.rb
52
52
  ```
53
53
 
54
- #### Generating Resources
54
+ ### Generating Resources
55
55
 
56
- For example you have model `User`, then run:
56
+ Assume you have model `User`, then run:
57
57
 
58
58
  ```bash
59
- rails g adminable:resource user
59
+ rails g adminable:resource users
60
60
  # => create app/controllers/adminable/users_controller.rb
61
61
  ```
62
62
 
63
63
  For namespaced models, like `Blog::Post`, use:
64
64
 
65
65
  ```bash
66
- rails g adminable:resource blog/post
66
+ rails g adminable:resource blog/posts
67
67
  # => create app/controllers/adminable/blog/posts_controller.rb
68
68
  ```
69
69
 
70
- #### Customizing Attributes
70
+ ### Customizing Fields
71
71
 
72
- You can update attributes with simple DSL inside `set_attributes` block:
73
-
74
- ##### For existing attributes
72
+ Change fields as you like inside `fields` method array:
75
73
 
76
74
  ```ruby
77
- set(name, options = {})
78
- ```
79
-
80
- ##### For new attributes
81
-
82
- ```ruby
83
- add(name, type, options = {})
75
+ class Adminable::Blog::PostsController < Adminable::ResourcesController
76
+ def fields
77
+ [
78
+ Adminable::Fields::String.new(:title),
79
+ Adminable::Fields::Text.new(:body),
80
+ Adminable::Fields::Float.new(:rating, form: false),
81
+ Adminable::Fields::Boolean.new(:published),
82
+ Adminable::Fields::BelongsTo.new(:user),
83
+ Adminable::Fields::HasMany.new(:blog_comments)
84
+ ]
85
+ end
86
+ end
84
87
  ```
85
88
 
86
- ##### Attributes Parameters
87
-
88
- * `index` - (`true` or `false`) - Shows attribute on index page.
89
- * `form` - (`true` or `false`) - Shows attribute on new/edit page.
90
- * `center` - (`true` or `false`) - Adds `text-align: center` for attribute value on index page.
91
- * `search` - (`true` or `false`) - Enables search for this attribute.
89
+ ### Fields Parameters
92
90
 
93
- ##### Examples
91
+ #### index
92
+ `true` or `false`, default: `true`.
94
93
 
95
- ```ruby
96
- class Adminable::Blog::PostsController < Adminable::ResourcesController
97
- set_attributes do |attributes|
98
- # Enables search for title column
99
- attributes.set :title, search: true
94
+ Shows field on index page.
100
95
 
101
- # Hides title from new and edit pages
102
- attributes.set :title, form: true
96
+ #### form
97
+ `true` or `false`, default: `true`.
103
98
 
104
- # Adds wysiwyg plugin and hides from index table
105
- attributes.set :text, wysiwyg: true, index: false
99
+ Shows field on new/edit page.
106
100
 
107
- # Adds new attribute `password` with type `string` and some options
108
- attributes.add :password, :string, wysiwyg: true, index: false
101
+ #### center
102
+ `true` or `false`, default `true` for `integer`, `boolean`, `float` and `decimal` fields, `false` otherwise.
109
103
 
110
- # Adds new attribute `author`
111
- attributes << Adminable::Attributes::Types::String.new(:author)
104
+ Adds `text-align: center` for field value on index page.
112
105
 
113
- # Allows search for multiple attributes
114
- attributes.set :title, :body, search: true
115
- end
116
- end
117
- ```
106
+ #### search
107
+ `true` or `false`, default: `false`.
108
+ Enables search for this field.
118
109
 
119
- ##### See Also
110
+ ### See Also
120
111
 
121
112
  * Configured controller for Devise model: [app/controllers/adminable/users_controller.rb](https://github.com/droptheplot/adminable/blob/master/spec/dummy/app/controllers/adminable/users_controller.rb)
122
113
 
123
- ## Built-in Attributes
124
-
125
- List of attributes with default parameters.
126
-
127
- | | index | form | center | wysiwyg |
128
- |------------|-------|------|--------|---------|
129
- | String | + | + | | |
130
- | Text | + | + | | + |
131
- | Integer | + | + | + | |
132
- | Float | + | + | + | |
133
- | Decimal | + | + | + | |
134
- | Date | + | + | | |
135
- | DateTime | + | + | | |
136
- | Time | + | + | | |
137
- | Timestamp | + | + | | |
138
- | Boolean | + | + | + | |
139
- | Belongs To | | + | | |
140
- | Has Many | | + | | |
114
+ ## Built-in Fields
115
+
116
+ * String
117
+ * Text
118
+ * Integer
119
+ * Float
120
+ * Decimal
121
+ * Date
122
+ * DateTime
123
+ * Time
124
+ * Timestamp
125
+ * Boolean
126
+ * Belongs To
127
+ * Has Many
141
128
 
142
129
  ## Generating Partials
143
130
 
@@ -146,7 +133,7 @@ You can use generator to copy original partial to your application.
146
133
  `rails g adminable:partial [layout] [type] [resource]`
147
134
 
148
135
  * `layout` - `index` or `form`.
149
- * `type` - `string`, `text` etc. See [Built-in Attributes](#built-in-attributes).
136
+ * `type` - `string`, `text` etc. See [Built-in Fields](#built-in-fields).
150
137
  * `resource` - Use controller name (e.g. `users`) to replace partial only for single controller or leave blank to replace partials for all controllers.
151
138
 
152
139
  ## F.A.Q
@@ -9,6 +9,7 @@ module Adminable
9
9
  end
10
10
 
11
11
  before_action :set_entry, only: [:edit, :update, :destroy]
12
+ before_action :set_fields, only: [:index, :new, :edit, :create, :update]
12
13
 
13
14
  before_action do
14
15
  append_view_path(
@@ -23,7 +24,7 @@ module Adminable
23
24
  def index
24
25
  @q = @resource.model.ransack(params[:q])
25
26
  @entries = Adminable::Presenters::Entries.new(
26
- @q.result.includes(*@resource.includes).order(id: :desc)
27
+ @q.result.includes(*includes).order(id: :desc)
27
28
  .page(params[:page]).per(25)
28
29
  )
29
30
  end
@@ -74,32 +75,6 @@ module Adminable
74
75
  )
75
76
  end
76
77
 
77
- # Calls from children controller class to manage resource attributes
78
- # @example Update attributes for Adminable::Blog::PostsController
79
- # # app/controllers/adminable/blog/posts_controller.rb
80
- #
81
- # set_attributes do |attributes|
82
- # # Enables search for title column
83
- # attributes.set :title, search: true
84
- #
85
- # # Hides title from new and edit pages
86
- # attributes.set :title, form: true
87
- #
88
- # # Adds wysiwyg plugin and hides from index table
89
- # attributes.set :text, wysiwyg: true, index: false
90
- #
91
- # # Adds new attribute `password` with type `string` and some options
92
- # attributes.add :password, :string, wysiwyg: true, index: false
93
- #
94
- # # Adds new attribute `author`
95
- # attributes << Adminable::Attributes::Types::String.new(:author)
96
- # end
97
- def self.set_attributes
98
- before_action do
99
- @resource.attributes.configure { yield(@resource.attributes) }
100
- end
101
- end
102
-
103
78
  private
104
79
 
105
80
  def set_entry
@@ -107,14 +82,30 @@ module Adminable
107
82
  @entry = Adminable::Presenters::Entry.new(entry)
108
83
  end
109
84
 
85
+ def set_fields
86
+ @fields = Adminable::Presenters::Fields.new(fields)
87
+ end
88
+
110
89
  def resource_model_name
111
90
  controller_path.sub(%r{^adminable/}, '')
112
91
  end
113
92
 
114
93
  def resource_params
115
94
  params.require(@resource.model.model_name.param_key).permit(
116
- *@resource.attributes.form.map(&:strong_parameter)
95
+ *fields.map(&:strong_parameter)
117
96
  )
118
97
  end
98
+
99
+ def fields
100
+ raise Adminable::FieldsNotDefined
101
+ end
102
+
103
+ def includes
104
+ association_fields = fields.select do |field|
105
+ %i(belongs_to has_many).include?(field.type)
106
+ end
107
+
108
+ association_fields.any? ? association_fields.map(&:name) : false
109
+ end
119
110
  end
120
111
  end
@@ -1,7 +1,7 @@
1
1
  = form_for @entry, method: (@entry.persisted? ? :patch : :post) do |f|
2
- - @resource.attributes.form.each do |attribute|
2
+ - @fields.form.each do |field|
3
3
  %fieldset.form-group
4
- = render attribute.form_partial_path, entry: @entry, attribute: attribute
4
+ = render field.form_partial_path, entry: @entry, field: field
5
5
  %fieldset.form-group
6
6
  = f.submit t('adminable.buttons.submit'), class: 'btn btn-primary'
7
7
  = link_to t('adminable.buttons.back'), polymorphic_path(@resource.model),
@@ -1,9 +1,9 @@
1
1
  .card.bg-faded
2
2
  .card-block
3
3
  = search_form_for @q do |f|
4
- - @resource.attributes.search.each do |attribute|
4
+ - @fields.search.each do |field|
5
5
  %fieldset.form-group
6
- = f.label attribute.ransack_name, @resource.model.human_attribute_name(attribute.name),
6
+ = f.label field.ransack_name, @resource.model.human_attribute_name(field.name),
7
7
  class: 'text-muted'
8
- = f.search_field attribute.ransack_name, class: 'form-control'
8
+ = f.search_field field.ransack_name, class: 'form-control'
9
9
  = f.submit t('adminable.buttons.search'), class: 'btn btn-primary-outline'
@@ -1,11 +1,11 @@
1
- = render 'adminable/shared/label', attribute: attribute
2
- = hidden_field_tag "#{@resource.model.model_name.param_key}[#{attribute.key}]", nil
1
+ = render 'adminable/shared/label', field: field
2
+ = hidden_field_tag "#{@resource.model.model_name.param_key}[#{field.key}]", nil
3
3
  #clusterizeScrollArea.clusterize-scroll.associations
4
4
  #clusterizeContentArea.clusterize-content
5
- - attribute.association.entries.each do |association_entry|
5
+ - Adminable::Presenters::Entries.new(entry.association(field.name).klass.all).each do |association_entry|
6
6
  .association
7
7
  %label.c-input.c-radio.m-a-0
8
- = radio_button_tag "#{@resource.model.model_name.param_key}[#{attribute.key}]",
9
- association_entry.id, entry.send(attribute.key) == association_entry.id
8
+ = radio_button_tag "#{@resource.model.model_name.param_key}[#{field.key}]",
9
+ association_entry.id, entry.send(field.key) == association_entry.id
10
10
  %span.c-indicator
11
11
  = association_entry.link_to_self
@@ -1,6 +1,6 @@
1
1
  %label.c-input.c-checkbox
2
- = hidden_field_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]", 0
3
- = check_box_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]", 1,
4
- entry.send(attribute.key)
2
+ = hidden_field_tag "#{@resource.model.model_name.param_key}[#{field.name}]", 0
3
+ = check_box_tag "#{@resource.model.model_name.param_key}[#{field.name}]", 1,
4
+ entry.send(field.key)
5
5
  %span.c-indicator
6
- = @resource.model.human_attribute_name(attribute.name)
6
+ = @resource.model.human_attribute_name(field.name)
@@ -1,3 +1,3 @@
1
- = render 'adminable/shared/label', attribute: attribute
2
- = date_field_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]",
3
- entry[attribute.name], class: 'form-control'
1
+ = render 'adminable/shared/label', field: field
2
+ = date_field_tag "#{@resource.model.model_name.param_key}[#{field.name}]",
3
+ entry[field.name], class: 'form-control'
@@ -1,3 +1,3 @@
1
- = render 'adminable/shared/label', attribute: attribute
2
- = datetime_field_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]",
3
- entry[attribute.name], class: 'form-control'
1
+ = render 'adminable/shared/label', field: field
2
+ = datetime_field_tag "#{@resource.model.model_name.param_key}[#{field.name}]",
3
+ entry[field.name], class: 'form-control'
@@ -1,3 +1,3 @@
1
- = render 'adminable/shared/label', attribute: attribute
2
- = number_field_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]",
3
- entry[attribute.name], class: 'form-control'
1
+ = render 'adminable/shared/label', field: field
2
+ = number_field_tag "#{@resource.model.model_name.param_key}[#{field.name}]",
3
+ entry[field.name], class: 'form-control'
@@ -1,3 +1,3 @@
1
- = render 'adminable/shared/label', attribute: attribute
2
- = number_field_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]",
3
- entry[attribute.name], class: 'form-control'
1
+ = render 'adminable/shared/label', field: field
2
+ = number_field_tag "#{@resource.model.model_name.param_key}[#{field.name}]",
3
+ entry[field.name], class: 'form-control'
@@ -1,12 +1,12 @@
1
- = render 'adminable/shared/label', attribute: attribute
2
- = hidden_field_tag "#{@resource.model.model_name.param_key}[#{attribute.key}][]", nil
1
+ = render 'adminable/shared/label', field: field
2
+ = hidden_field_tag "#{@resource.model.model_name.param_key}[#{field.key}][]", nil
3
3
  #clusterizeScrollArea.clusterize-scroll.associations
4
4
  #clusterizeContentArea.clusterize-content
5
- - attribute.association.entries.each do |association_entry|
5
+ - Adminable::Presenters::Entries.new(entry.association(field.name).klass.all).each do |association_entry|
6
6
  .association
7
7
  %label.c-input.c-checkbox.m-a-0
8
- = check_box_tag "#{@resource.model.model_name.param_key}[#{attribute.key}][]",
9
- association_entry.id, entry.send(attribute.key).include?(association_entry.id)
8
+ = check_box_tag "#{@resource.model.model_name.param_key}[#{field.key}][]",
9
+ association_entry.id, entry.send(field.key).include?(association_entry.id)
10
10
  %span.c-indicator
11
11
  = link_to association_entry.to_name,
12
12
  edit_polymorphic_path(association_entry),
@@ -1,3 +1,3 @@
1
- = render 'adminable/shared/label', attribute: attribute
2
- = number_field_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]",
3
- entry[attribute.name], class: 'form-control'
1
+ = render 'adminable/shared/label', field: field
2
+ = number_field_tag "#{@resource.model.model_name.param_key}[#{field.name}]",
3
+ entry[field.name], class: 'form-control'
@@ -1,3 +1,3 @@
1
- = render 'adminable/shared/label', attribute: attribute
2
- = text_field_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]",
3
- entry[attribute.name], class: 'form-control'
1
+ = render 'adminable/shared/label', field: field
2
+ = text_field_tag "#{@resource.model.model_name.param_key}[#{field.name}]",
3
+ entry[field.name], class: 'form-control'
@@ -1,4 +1,4 @@
1
- = render 'adminable/shared/label', attribute: attribute
2
- = text_area_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]",
3
- entry[attribute.name],
4
- class: "form-control #{ 'wysiwyg' if attribute.options[:wysiwyg] }", rows: 5
1
+ = render 'adminable/shared/label', field: field
2
+ = text_area_tag "#{@resource.model.model_name.param_key}[#{field.name}]",
3
+ entry[field.name],
4
+ class: "form-control #{ 'wysiwyg' if field.options[:wysiwyg] }", rows: 5
@@ -1,3 +1,3 @@
1
- = render 'adminable/shared/label', attribute: attribute
2
- = text_field_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]",
3
- entry[attribute.name], class: 'form-control'
1
+ = render 'adminable/shared/label', field: field
2
+ = text_field_tag "#{@resource.model.model_name.param_key}[#{field.name}]",
3
+ entry[field.name], class: 'form-control'
@@ -1,3 +1,3 @@
1
- = render 'adminable/shared/label', attribute: attribute
2
- = text_field_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]",
3
- entry[attribute.name], class: 'form-control'
1
+ = render 'adminable/shared/label', field: field
2
+ = text_field_tag "#{@resource.model.model_name.param_key}[#{field.name}]",
3
+ entry[field.name], class: 'form-control'
@@ -4,30 +4,30 @@
4
4
  = link_to t('adminable.buttons.new', resource: @resource.model.model_name.human),
5
5
  new_polymorphic_path(@resource.model), class: 'btn btn-primary pull-md-right m-b-2'
6
6
  .row
7
- %div{ :class => (@resource.attributes.search.any? ? 'col-md-9' : 'col-md-12') }
7
+ %div{ :class => (@fields.search.any? ? 'col-md-9' : 'col-md-12') }
8
8
  .table-responsive.m-b-3
9
9
  %table.table.table-striped
10
10
  %thead
11
11
  %tr
12
- - @resource.attributes.index.each do |attribute|
13
- %th.text-nowrap{ :class => ('text-md-center' if attribute.options[:center]) }
14
- = sort_link(@q, attribute.name, hide_indicator: true)
12
+ - @fields.index.each do |field|
13
+ %th.text-nowrap{ :class => ('text-md-center' if field.options[:center]) }
14
+ = sort_link(@q, field.name, hide_indicator: true)
15
15
  %th
16
16
  %tbody
17
17
  - @entries.each do |entry|
18
18
  %tr
19
- - @resource.attributes.index.each do |attribute|
20
- %td{ :class => ('text-md-center' if attribute.options[:center]) }
21
- = render attribute.index_partial_path, entry: entry,
22
- attribute: attribute, value: entry.public_send(attribute.name)
19
+ - @fields.index.each do |field|
20
+ %td{ :class => ('text-md-center' if field.options[:center]) }
21
+ = render field.index_partial_path, entry: entry,
22
+ field: field, value: entry.public_send(field.name)
23
23
  %td.text-nowrap.text-md-right
24
24
  = entry.link_to_edit_small
25
25
  = entry.link_to_delete_small
26
26
  - if @entries.empty?
27
27
  %tr
28
- %td.text-md-center.text-muted{ :colspan => @resource.attributes.index.size + 1 }
28
+ %td.text-md-center.text-muted{ :colspan => @fields.index.size + 1 }
29
29
  No data available
30
- - if @resource.attributes.search.any?
30
+ - if @fields.search.any?
31
31
  .col-md-3.hidden-sm-down
32
32
  = render 'search'
33
33
  = paginate @entries, views_prefix: 'adminable'
@@ -1,8 +1,8 @@
1
- = label_tag attribute.name do
2
- = @resource.model.human_attribute_name(attribute.name)
3
- - if attribute.options[:required]
1
+ = label_tag field.name do
2
+ = @resource.model.human_attribute_name(field.name)
3
+ - if field.options[:required]
4
4
  %span.text-muted.m-l-1
5
5
  %i.fa.fa-exclamation-circle{ 'data-toggle' => :tooltip, 'data-placement' => :right, :title => 'Required' }
6
- - if %i(belongs_to has_many).include?(attribute.type)
6
+ - if %i(belongs_to has_many).include?(field.type)
7
7
  %span.text-muted.m-l-1.uncheck-associations
8
8
  %i.fa.fa-remove{ 'data-toggle' => :tooltip, 'data-placement' => :right, :title => 'Uncheck all' }
@@ -7,24 +7,23 @@ require 'adminable/resource'
7
7
  require 'adminable/presenters/base'
8
8
  require 'adminable/presenters/entry'
9
9
  require 'adminable/presenters/entries'
10
+ require 'adminable/presenters/fields'
10
11
 
11
- require 'adminable/attributes/collection'
12
- require 'adminable/attributes/association'
12
+ require 'adminable/field_collector'
13
13
 
14
- require 'adminable/attributes/base'
15
-
16
- require 'adminable/attributes/types/belongs_to'
17
- require 'adminable/attributes/types/boolean'
18
- require 'adminable/attributes/types/date'
19
- require 'adminable/attributes/types/datetime'
20
- require 'adminable/attributes/types/decimal'
21
- require 'adminable/attributes/types/float'
22
- require 'adminable/attributes/types/has_many'
23
- require 'adminable/attributes/types/integer'
24
- require 'adminable/attributes/types/string'
25
- require 'adminable/attributes/types/text'
26
- require 'adminable/attributes/types/time'
27
- require 'adminable/attributes/types/timestamp'
14
+ require 'adminable/fields/base'
15
+ require 'adminable/fields/belongs_to'
16
+ require 'adminable/fields/boolean'
17
+ require 'adminable/fields/date'
18
+ require 'adminable/fields/datetime'
19
+ require 'adminable/fields/decimal'
20
+ require 'adminable/fields/float'
21
+ require 'adminable/fields/has_many'
22
+ require 'adminable/fields/integer'
23
+ require 'adminable/fields/string'
24
+ require 'adminable/fields/text'
25
+ require 'adminable/fields/time'
26
+ require 'adminable/fields/timestamp'
28
27
 
29
28
  require 'haml-rails'
30
29
  require 'sass-rails'
@@ -1,7 +1,10 @@
1
1
  module Adminable
2
- class AttributeNotImplemented < StandardError
2
+ class FieldsNotDefined < StandardError
3
3
  end
4
4
 
5
- class AttributeNotFound < StandardError
5
+ class FieldNotImplemented < StandardError
6
+ end
7
+
8
+ class FieldNotFound < StandardError
6
9
  end
7
10
  end
@@ -0,0 +1,53 @@
1
+ module Adminable
2
+ class FieldCollector
3
+ # @return [ActiveRecord::Base] activerecord model class
4
+ # @example
5
+ # Adminable::Fields::Collection.new(User).model
6
+ # # => User(id: integer, email: string, password_hash: string)
7
+ attr_reader :model
8
+
9
+ # @return [Array] fields from activerecord model
10
+ attr_reader :all
11
+
12
+ # @param model [ActiveRecord::Base] activerecord model class
13
+ def initialize(model)
14
+ @model = model
15
+ @all ||= columns + associations
16
+ end
17
+
18
+ # Collects fields from model columns
19
+ # @return [Array]
20
+ #
21
+ # rubocop:disable Metrics/MethodLength
22
+ def columns
23
+ @columns ||= [].tap do |fields|
24
+ @model.columns.reject { |a| a.name.match(/_id$/) }.each do |column|
25
+ fields << resolve(column.type, column.name)
26
+ end
27
+ end
28
+ end
29
+
30
+ # Collects fields from model associations
31
+ # @return [Array]
32
+ def associations
33
+ @associations ||= [].tap do |fields|
34
+ @model.reflect_on_all_associations.each do |association|
35
+ fields << resolve(association.macro, association.name)
36
+ end
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def resolve(type, name)
43
+ class_name = "adminable/fields/#{type}".classify
44
+ "#{class_name}.new(:#{name})"
45
+ end
46
+
47
+ def required?(name)
48
+ @model.validators_on(name).any? do |validator|
49
+ validator.class == ActiveRecord::Validations::PresenceValidator
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,44 +1,52 @@
1
1
  module Adminable
2
- module Attributes
3
- # Base class for attributes types
2
+ module Fields
3
+ # Base class for fields
4
4
  # @note Cannot be initialized
5
5
  class Base
6
- attr_reader :name, :options, :key, :strong_parameter, :association
6
+ # @return [Symbol] field name
7
+ attr_reader :name
7
8
 
8
- # @param name [Symbol] attribute name e.g. `:id` or `:title`
9
+ # @return [Hash] default options for field
10
+ attr_reader :options
11
+
12
+ # @param name [Symbol] field name e.g. `:id` or `:title`
9
13
  # @param options [Hash] options, see {default_options}
10
14
  def initialize(name, options = {})
11
15
  raise 'Base class cannot be initialized' if self.class == Base
12
16
 
13
17
  @name = name.to_sym
14
18
  @options = default_options.merge(options)
15
-
16
- @association = Adminable::Attributes::Association.new(
17
- options[:association]
18
- ) if options[:association]
19
19
  end
20
20
 
21
+ # @return [Symbol] field form key
21
22
  def key
22
23
  @key ||= name
23
24
  end
24
25
 
26
+ # @return [Symbol] controller strong parameters key
25
27
  def strong_parameter
26
28
  @strong_parameter ||= key
27
29
  end
28
30
 
31
+ # @return [String] ransack form key
29
32
  def ransack_name
30
33
  @ransack_name ||= "#{name}_cont"
31
34
  end
32
35
 
33
- # @return [Symbol] class type e.g. `:text` for Adminable::Attributes::Text
36
+ # @return [Symbol] field type
37
+ # @example
38
+ # Adminable::Fields::String.new(:title).type
39
+ # # => :string
34
40
  def type
35
41
  @type ||= self.class.name.demodulize.underscore.to_sym
36
42
  end
37
43
 
44
+ # @return [String] path to field index partial
38
45
  def index_partial_path
39
46
  "index/#{type}"
40
47
  end
41
48
 
49
+ # @return [String] path to field form partial
42
50
  def form_partial_path
43
51
  "form/#{type}"
44
52
  end
@@ -47,12 +55,12 @@ module Adminable
47
55
 
48
56
  def default_options
49
57
  {
50
- index: %i(belongs_to has_many).exclude?(type),
58
+ index: true,
59
+ form: true,
60
+ wysiwyg: false,
51
61
  search: false,
52
- form: %i(id created_at updated_at).exclude?(name),
53
62
  required: false,
54
- center: %i(integer boolean float decimal).include?(type),
55
- wysiwyg: false
63
+ center: %i(integer boolean float decimal).include?(type)
56
64
  }
57
65
  end
58
66
  end
@@ -0,0 +1,9 @@
1
+ module Adminable
2
+ module Fields
3
+ class BelongsTo < Base
4
+ def key
5
+ "#{name}_id"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module Adminable
2
+ module Fields
3
+ class Boolean < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Adminable
2
+ module Fields
3
+ class Date < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Adminable
2
+ module Fields
3
+ class Datetime < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Adminable
2
+ module Fields
3
+ class Decimal < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Adminable
2
+ module Fields
3
+ class Float < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ module Adminable
2
+ module Fields
3
+ class HasMany < Base
4
+ def key
5
+ "#{@name.to_s.singularize}_ids"
6
+ end
7
+
8
+ def strong_parameter
9
+ { key => [] }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ module Adminable
2
+ module Fields
3
+ class Integer < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Adminable
2
+ module Fields
3
+ class String < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Adminable
2
+ module Fields
3
+ class Text < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Adminable
2
+ module Fields
3
+ class Time < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Adminable
2
+ module Fields
3
+ class Timestamp < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,17 @@
1
+ module Adminable
2
+ module Presenters
3
+ class Fields < SimpleDelegator
4
+ def index
5
+ select { |field| field.options[:index] }
6
+ end
7
+
8
+ def form
9
+ select { |field| field.options[:form] }
10
+ end
11
+
12
+ def search
13
+ select { |field| field.options[:search] }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,6 +1,8 @@
1
1
  module Adminable
2
2
  class Resource
3
- attr_reader :name, :model, :attributes
3
+ include Comparable
4
+
5
+ attr_reader :name, :model, :fields
4
6
 
5
7
  # @param name [String] resource name, usually same as the model name
6
8
  def initialize(name)
@@ -13,22 +15,8 @@ module Adminable
13
15
  @route ||= @model.name.underscore.pluralize.tr('/', '_')
14
16
  end
15
17
 
16
- # @return [Array] of associations names for ActiveRecord queries
17
- def includes
18
- @includes ||= if attributes.associations.present?
19
- attributes.associations.map(&:name)
20
- else
21
- false
22
- end
23
- end
24
-
25
- # @return [Array] collection, see {Adminable::Attributes::Collection}
26
- def attributes
27
- @attributes ||= Adminable::Attributes::Collection.new(@model)
28
- end
29
-
30
- def ==(other)
31
- other.is_a?(Adminable::Resource) && name == other.name
18
+ def <=>(other)
19
+ other.is_a?(Adminable::Resource) && name <=> other.name
32
20
  end
33
21
  end
34
22
  end
@@ -1,3 +1,3 @@
1
1
  module Adminable
2
- VERSION = '0.0.5'.freeze
2
+ VERSION = '0.0.6'.freeze
3
3
  end
@@ -1,2 +1,7 @@
1
- class <%= resource_class %>Controller < Adminable::ResourcesController
1
+ class <%= resource_class_name %>Controller < Adminable::ResourcesController
2
+ def fields
3
+ [
4
+ <%= fields.join(",\n\t\t\t") %>
5
+ ]
6
+ end
2
7
  end
@@ -20,9 +20,17 @@ module Adminable
20
20
  name.underscore.pluralize
21
21
  end
22
22
 
23
- def resource_class
23
+ def resource_class_name
24
24
  "adminable/#{resource_name}".classify.pluralize
25
25
  end
26
+
27
+ def model_class
28
+ name.classify.constantize
29
+ end
30
+
31
+ def fields
32
+ Adminable::FieldCollector.new(model_class).all
33
+ end
26
34
  end
27
35
  end
28
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adminable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergey Novikov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-08 00:00:00.000000000 Z
11
+ date: 2016-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -370,27 +370,27 @@ files:
370
370
  - config/locales/adminable.ru.yml
371
371
  - config/routes.rb
372
372
  - lib/adminable.rb
373
- - lib/adminable/attributes/association.rb
374
- - lib/adminable/attributes/base.rb
375
- - lib/adminable/attributes/collection.rb
376
- - lib/adminable/attributes/types/belongs_to.rb
377
- - lib/adminable/attributes/types/boolean.rb
378
- - lib/adminable/attributes/types/date.rb
379
- - lib/adminable/attributes/types/datetime.rb
380
- - lib/adminable/attributes/types/decimal.rb
381
- - lib/adminable/attributes/types/float.rb
382
- - lib/adminable/attributes/types/has_many.rb
383
- - lib/adminable/attributes/types/integer.rb
384
- - lib/adminable/attributes/types/string.rb
385
- - lib/adminable/attributes/types/text.rb
386
- - lib/adminable/attributes/types/time.rb
387
- - lib/adminable/attributes/types/timestamp.rb
388
373
  - lib/adminable/configuration.rb
389
374
  - lib/adminable/engine.rb
390
375
  - lib/adminable/errors.rb
376
+ - lib/adminable/field_collector.rb
377
+ - lib/adminable/fields/base.rb
378
+ - lib/adminable/fields/belongs_to.rb
379
+ - lib/adminable/fields/boolean.rb
380
+ - lib/adminable/fields/date.rb
381
+ - lib/adminable/fields/datetime.rb
382
+ - lib/adminable/fields/decimal.rb
383
+ - lib/adminable/fields/float.rb
384
+ - lib/adminable/fields/has_many.rb
385
+ - lib/adminable/fields/integer.rb
386
+ - lib/adminable/fields/string.rb
387
+ - lib/adminable/fields/text.rb
388
+ - lib/adminable/fields/time.rb
389
+ - lib/adminable/fields/timestamp.rb
391
390
  - lib/adminable/presenters/base.rb
392
391
  - lib/adminable/presenters/entries.rb
393
392
  - lib/adminable/presenters/entry.rb
393
+ - lib/adminable/presenters/fields.rb
394
394
  - lib/adminable/resource.rb
395
395
  - lib/adminable/version.rb
396
396
  - lib/generators/adminable/install/templates/application_controller.rb
@@ -1,14 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- class Association
4
- attr_reader :reflection, :model, :entries
5
-
6
- # @param reflection [Object] ActiveRecord::Reflection::HasManyReflection
7
- def initialize(reflection)
8
- @reflection = reflection
9
- @model = @reflection.klass
10
- @entries = Adminable::Presenters::Entries.new(@model)
11
- end
12
- end
13
- end
14
- end
@@ -1,116 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- class Collection
4
- include Enumerable
5
- extend Forwardable
6
-
7
- def_delegators :@all, :[], :<<, :each, :first, :last, :push, :unshift
8
-
9
- attr_reader :model, :all
10
-
11
- # @param model [Class] model from Rails application e.g. `User` or `Post`
12
- def initialize(model)
13
- @model = model
14
- @all ||= columns + associations
15
- end
16
-
17
- def index
18
- all.select { |attribute| attribute.options[:index] }
19
- end
20
-
21
- def form
22
- all.select { |attribute| attribute.options[:form] }
23
- end
24
-
25
- def search
26
- all.select { |attribute| attribute.options[:search] }
27
- end
28
-
29
- # Collects attributes from model columns
30
- # @return [Array]
31
- #
32
- # rubocop:disable Metrics/MethodLength
33
- def columns
34
- @columns ||= [].tap do |attributes|
35
- @model.columns.reject { |a| a.name.match(/_id$/) }.each do |column|
36
- begin
37
- attributes << resolve(column.type).new(
38
- column.name,
39
- required: required?(column.name)
40
- )
41
- rescue Adminable::AttributeNotImplemented
42
- next
43
- end
44
- end
45
- end
46
- end
47
-
48
- # Collects attributes from model associations
49
- # @return [Array]
50
- def associations
51
- @associations ||= [].tap do |attributes|
52
- @model.reflect_on_all_associations.each do |association|
53
- attributes << resolve(association.macro).new(
54
- association.name,
55
- required: required?(association.name),
56
- association: association
57
- )
58
- end
59
- end
60
- end
61
-
62
- def configure
63
- yield
64
- end
65
-
66
- # Changes options for given attribute
67
- # @param name [Symbol] name of attribute e.g. `:title`
68
- # @param options [Hash] options to update
69
- def set(*args)
70
- options = args.extract_options!
71
- names = args
72
-
73
- options.each do |key, value|
74
- names.each do |name|
75
- get(name).options[key] = value
76
- end
77
- end
78
- end
79
-
80
- # Finds attribute by name
81
- # @param name [Symbol] name of attribute e.g. `:title`
82
- # @return [Object] e.g. `Adminable::Attribute::Types::String` for `:title`
83
- def get(name)
84
- @all.find { |attribute| attribute.name == name } ||
85
- raise(
86
- Adminable::AttributeNotFound,
87
- "couldn't find attribute with name `#{name}`"
88
- )
89
- end
90
-
91
- # Adds new attribute to collection
92
- # @param name [Symbol] name of attribute e.g. `:title`
93
- # @param type [Symbol] type of attribute e.g. `:string`
94
- def add(name, type, options = {})
95
- @all << resolve(type).new(name, **options)
96
- end
97
-
98
- private
99
-
100
- def resolve(type)
101
- "adminable/attributes/types/#{type}".classify.constantize
102
- rescue NameError
103
- raise(
104
- Adminable::AttributeNotImplemented,
105
- "type `#{type}` is not supported yet."
106
- )
107
- end
108
-
109
- def required?(name)
110
- @model.validators_on(name).any? do |validator|
111
- validator.class == ActiveRecord::Validations::PresenceValidator
112
- end
113
- end
114
- end
115
- end
116
- end
@@ -1,11 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- module Types
4
- class BelongsTo < Base
5
- def key
6
- @association.reflection.foreign_key
7
- end
8
- end
9
- end
10
- end
11
- end
@@ -1,8 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- module Types
4
- class Boolean < Base
5
- end
6
- end
7
- end
8
- end
@@ -1,8 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- module Types
4
- class Date < Base
5
- end
6
- end
7
- end
8
- end
@@ -1,8 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- module Types
4
- class Datetime < Base
5
- end
6
- end
7
- end
8
- end
@@ -1,8 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- module Types
4
- class Decimal < Base
5
- end
6
- end
7
- end
8
- end
@@ -1,8 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- module Types
4
- class Float < Base
5
- end
6
- end
7
- end
8
- end
@@ -1,15 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- module Types
4
- class HasMany < Base
5
- def key
6
- @key = "#{@name.to_s.singularize}_ids"
7
- end
8
-
9
- def strong_parameter
10
- { key => [] }
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,8 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- module Types
4
- class Integer < Base
5
- end
6
- end
7
- end
8
- end
@@ -1,8 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- module Types
4
- class String < Base
5
- end
6
- end
7
- end
8
- end
@@ -1,8 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- module Types
4
- class Text < Base
5
- end
6
- end
7
- end
8
- end
@@ -1,8 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- module Types
4
- class Time < Base
5
- end
6
- end
7
- end
8
- end
@@ -1,8 +0,0 @@
1
- module Adminable
2
- module Attributes
3
- module Types
4
- class Timestamp < Base
5
- end
6
- end
7
- end
8
- end