active_element 0.0.11 → 0.0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/Gemfile +2 -1
- data/Gemfile.lock +10 -3
- data/app/assets/javascripts/active_element/highlight.js +311 -0
- data/app/assets/javascripts/active_element/json_field.js +51 -20
- data/app/assets/javascripts/active_element/popover.js +6 -4
- data/app/assets/javascripts/active_element/text_search_field.js +13 -1
- data/app/assets/stylesheets/active_element/_dark.scss +1 -1
- data/app/assets/stylesheets/active_element/application.scss +39 -1
- data/app/controllers/concerns/active_element/default_controller_actions.rb +7 -7
- data/app/views/active_element/components/fields/_json.html.erb +3 -2
- data/app/views/active_element/components/form/_field.html.erb +2 -1
- data/app/views/active_element/components/form/_json.html.erb +2 -0
- data/app/views/active_element/components/form/_label.html.erb +8 -1
- data/app/views/active_element/components/form/_templates.html.erb +8 -5
- data/app/views/active_element/components/form/_text_search.html.erb +1 -1
- data/app/views/active_element/components/form.html.erb +2 -2
- data/app/views/active_element/components/table/_field.html.erb +1 -1
- data/app/views/active_element/components/table/_ungrouped_collection.html.erb +1 -0
- data/app/views/active_element/components/table/item.html.erb +1 -0
- data/app/views/active_element/default_views/edit.html.erb +2 -2
- data/app/views/active_element/default_views/forbidden.html.erb +7 -0
- data/app/views/active_element/default_views/index.html.erb +7 -7
- data/app/views/active_element/default_views/new.html.erb +1 -1
- data/app/views/active_element/default_views/show.html.erb +3 -3
- data/app/views/layouts/active_element.html.erb +25 -4
- data/config/locales/en.yml +3 -0
- data/example_app/Gemfile.lock +1 -1
- data/example_app/app/controllers/pets_controller.rb +1 -0
- data/example_app/app/controllers/users_controller.rb +1 -0
- data/lib/active_element/components/form.rb +1 -8
- data/lib/active_element/components/text_search.rb +10 -1
- data/lib/active_element/components/util/display_value_mapping.rb +0 -2
- data/lib/active_element/components/util/form_field_mapping.rb +23 -10
- data/lib/active_element/components/util/numeric_field.rb +73 -0
- data/lib/active_element/components/util.rb +8 -0
- data/lib/active_element/controller_interface.rb +27 -30
- data/lib/active_element/controller_state.rb +44 -0
- data/lib/active_element/default_controller/actions.rb +3 -0
- data/lib/active_element/default_controller/controller.rb +145 -0
- data/lib/active_element/default_controller/json_params.rb +48 -0
- data/lib/active_element/default_controller/params.rb +97 -0
- data/lib/active_element/default_controller/search.rb +112 -0
- data/lib/active_element/default_controller.rb +10 -88
- data/lib/active_element/version.rb +1 -1
- data/lib/active_element.rb +1 -2
- data/rspec-documentation/_head.html.erb +2 -0
- data/rspec-documentation/pages/000-Introduction.md +8 -5
- data/rspec-documentation/pages/005-Setup.md +21 -28
- data/rspec-documentation/pages/010-Components/Form Fields.md +35 -0
- data/rspec-documentation/pages/015-Custom Controllers.md +32 -0
- data/rspec-documentation/pages/016-Default Controller.md +132 -0
- data/rspec-documentation/pages/Themes.md +3 -0
- metadata +15 -4
- data/lib/active_element/default_record_params.rb +0 -62
- data/lib/active_element/default_text_search.rb +0 -110
data/lib/active_element.rb
CHANGED
@@ -12,10 +12,9 @@ require_relative 'active_element/active_menu_link'
|
|
12
12
|
require_relative 'active_element/permissions_check'
|
13
13
|
require_relative 'active_element/permissions_report'
|
14
14
|
require_relative 'active_element/controller_interface'
|
15
|
+
require_relative 'active_element/controller_state'
|
15
16
|
require_relative 'active_element/controller_action'
|
16
17
|
require_relative 'active_element/default_controller'
|
17
|
-
require_relative 'active_element/default_record_params'
|
18
|
-
require_relative 'active_element/default_text_search'
|
19
18
|
require_relative 'active_element/pre_render_processors'
|
20
19
|
require_relative 'active_element/rails_component'
|
21
20
|
require_relative 'active_element/route'
|
@@ -3,6 +3,7 @@
|
|
3
3
|
<%= File.read('app/assets/javascripts/active_element/setup.js') %>
|
4
4
|
<%= File.read('app/assets/javascripts/active_element/json_field.js') %>
|
5
5
|
<%= File.read('app/assets/javascripts/active_element/text_search_field.js') %>
|
6
|
+
<%= File.read('app/assets/javascripts/active_element/popover.js') %>
|
6
7
|
ActiveElement.debug = true;
|
7
8
|
ActiveElement.getRequestId = () => 'fake-request-id';
|
8
9
|
const textSearchNames = <%= text_search_names.to_json %>;
|
@@ -24,6 +25,7 @@ window.fetch = (_, { body }) => {
|
|
24
25
|
<style>
|
25
26
|
<%= application_css %>
|
26
27
|
</style>
|
28
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.9.2/umd/popper.min.js" integrity="sha512-2rNj2KJ+D8s1ceNasTIex6z4HWyOnEYLVC3FigGOmyQCZc2eBXKgOxQmo3oKLHyfcj53uz4QMsRCWNbLd32Q1g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
27
29
|
<script>
|
28
30
|
/*!
|
29
31
|
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
@@ -1,18 +1,21 @@
|
|
1
1
|
# Introduction
|
2
2
|
|
3
|
-
_ActiveElement_
|
3
|
+
_ActiveElement_ is a [Ruby on Rails](https://rubyonrails.org/) framework primarily intended for building admin applications with minimal effort.
|
4
4
|
|
5
5
|
An [authorization framework](access-control.html) is provided, intended to work alongside existing frameworks such as [Devise](https://github.com/heartcombo/devise), [Pundit](https://github.com/varvet/pundit), and [CanCanCan](https://github.com/CanCanCommunity/cancancan).
|
6
6
|
|
7
|
+
_ActiveElement_ is designed to avoid the all-or-nothing approach that many frameworks provide, allowing you to build a fully functional administration tool in minutes, while still allowing you to customize every aspect of your application. _ActiveElement_ is just a _Rails_ application with extra features: when you need to build custom functionality, you do it the same way you would any other _Rails_ application and you can use as much or as little of _ActiveElement_ as you like.
|
8
|
+
|
9
|
+
Take a look at the [Setup Guide](setup.html) to build your first _ActiveElement_ application and see how easily you can mix in standard _Rails_ behaviours.
|
10
|
+
|
7
11
|
## Highlights
|
8
12
|
|
13
|
+
* Build an entire application by defining models and controllers with just a few lines of configuration in each controller.
|
14
|
+
* [Components](components.html) that can be re-used throughout your application.
|
9
15
|
* Feature-rich [forms](components/forms.html) including a powerful [JSON form field component](components/form-fields/json.html).
|
10
16
|
* Simple and secure [auto-suggest text search](components/form-fields/text-search.html) widgets.
|
11
|
-
* [Tables](components/tables.html) with built-in pagination and action buttons for viewing/editing/deleting records.
|
12
17
|
* [Decorators](decorators.html) for overriding default display fields with simple _Rails_ view partials.
|
13
|
-
* Automated [permissions](access-control/authorization/permissions.html) that can be applied to all application endpoints with minimal effort.
|
14
|
-
* Sensible defaults to help you build your application quickly while also allowing you to customize when needed.
|
15
|
-
* _ActiveElement_ attempts to provide a framework of familiar patterns that work with you instead of against you. It does not attempt to do everything for you and avoids behind-the-scenes magic where possible.
|
18
|
+
* Automated [route-based permissions](access-control/authorization/permissions.html) that can be applied to all application endpoints with minimal effort.
|
16
19
|
* [Bootstrap](https://getbootstrap.com/) styling with [customizable themes](themes.html).
|
17
20
|
|
18
21
|
See the [Setup Guide](setup.html) and browse the rest of the documentation for full usage examples.
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# Setup
|
2
2
|
|
3
|
-
To integrate _ActiveElement_ into your _Rails_ application, follow the steps below:
|
4
|
-
|
5
3
|
## Installation
|
6
4
|
|
7
5
|
Install the `active_element` gem by adding the following to your `Gemfile`:
|
@@ -20,7 +18,7 @@ $ bundle install
|
|
20
18
|
|
21
19
|
Inherit from `ActiveElement::ApplicationController` in the controller you want to use with _ActiveElement_. In most cases this will either be your main `ApplicationController`, or a namespaced admin area controller, e.g. `Admin::ApplicationController`. This will apply the default _ActiveElement_ layout which includes a [Navbar](components/navbar.html), [Theme Switcher](components/theme-switcher.html), and all the required _CSS_ and _Javascript_.
|
22
20
|
|
23
|
-
If you want to add custom content to the layout, see the [Hooks](hooks.html) documentation
|
21
|
+
If you want to add custom content to the layout, see the [Hooks](hooks.html) documentation, or if you want to use a completely custom layout, simply specify `layout 'my_layout'` in your `ApplicationController`.
|
24
22
|
|
25
23
|
```ruby
|
26
24
|
# app/controllers/application_controller.rb
|
@@ -30,23 +28,13 @@ class ApplicationController < ActiveElement::ApplicationController
|
|
30
28
|
end
|
31
29
|
```
|
32
30
|
|
33
|
-
##
|
31
|
+
## Default Controller Actions
|
34
32
|
|
35
|
-
|
33
|
+
_ActiveElement_ provides default controller actions for all controllers that inherit from `ActiveElement::ApplicationController` (directly or indirectly).
|
36
34
|
|
37
|
-
|
35
|
+
Each action provides boilerplate functionality to get your application off the ground as quickly as possible. See the [Default Controller](default-controller.html) for full details.
|
38
36
|
|
39
|
-
|
40
|
-
# app/controllers/users_controller.rb
|
41
|
-
|
42
|
-
class UsersController < ApplicationController
|
43
|
-
def index
|
44
|
-
@users = User.all
|
45
|
-
end
|
46
|
-
end
|
47
|
-
```
|
48
|
-
|
49
|
-
And your routes are defined something like this:
|
37
|
+
The below example creates a `/users` endpoint for your application with boilerplate to list, search, view, create, edit, and delete users:
|
50
38
|
|
51
39
|
```ruby
|
52
40
|
# config/routes.rb
|
@@ -56,20 +44,25 @@ Rails.application.routes.draw do
|
|
56
44
|
end
|
57
45
|
```
|
58
46
|
|
59
|
-
|
60
|
-
|
61
|
-
```erb
|
62
|
-
<%# app/views/users/index.html.erb %>
|
63
|
-
|
64
|
-
<%= active_element.component.page_title 'Users' %>
|
47
|
+
```ruby
|
48
|
+
# app/controllers/users_controller.rb
|
65
49
|
|
66
|
-
|
50
|
+
class UsersController < ApplicationController
|
51
|
+
active_element.listable_fields :name, :email, :created_at, order: :name
|
52
|
+
active_element.viewable_fields :name, :email, :created_at, :updated_at
|
53
|
+
active_element.editable_fields :name, :email
|
54
|
+
active_element.searchable_fields :name, :name, :created_at, :updated_at
|
55
|
+
active_element.deletable
|
56
|
+
end
|
67
57
|
```
|
68
58
|
|
69
|
-
|
59
|
+
```ruby
|
60
|
+
# app/models/user.rb
|
70
61
|
|
71
|
-
|
62
|
+
class User < ApplicationRecord
|
63
|
+
end
|
64
|
+
```
|
72
65
|
|
73
|
-
|
66
|
+
You can now browse to `/users` on your local development server and see all the default behaviour provided by _ActiveElement_.
|
74
67
|
|
75
|
-
|
68
|
+
See the [Default Controller](default-controller.html) and [Custom Controllers](custom-controllers.html) sections for more details.
|
@@ -44,3 +44,38 @@ end
|
|
44
44
|
|
45
45
|
it { is_expected.to include 'class="form-control my-class"' }
|
46
46
|
```
|
47
|
+
|
48
|
+
## Custom Fields
|
49
|
+
|
50
|
+
If you're using the [Default Controller](../default-controller.html) or you simply want to separate your configuration from your views, you can customize each form field by creating a file named `config/forms/<model>/<field>.yml`.
|
51
|
+
|
52
|
+
The `User` `email` field can be configured by creating `config/forms/user/email.yml`:
|
53
|
+
|
54
|
+
```yaml
|
55
|
+
# config/forms/user/email.yml
|
56
|
+
|
57
|
+
type: email_field
|
58
|
+
options:
|
59
|
+
class: 'form-control my-email-field-class'
|
60
|
+
description: 'We will use your email address to send your account details.'
|
61
|
+
placeholder: 'Enter your email address, e.g. user@example.com'
|
62
|
+
```
|
63
|
+
|
64
|
+
```rspec:html
|
65
|
+
subject do
|
66
|
+
active_element.component.form model: User.new,
|
67
|
+
fields: [:email, :name, :date_of_birth]
|
68
|
+
end
|
69
|
+
|
70
|
+
it { is_expected.to include 'class="form-control my-email-field-class"' }
|
71
|
+
```
|
72
|
+
|
73
|
+
The `options` configuration receives a small number of options specific to _ActiveElement_ such as `description` and [Text Search](form-fields/text-search.html) configuration, otherwise they are passed directly to the underlying _Rails_ form helper.
|
74
|
+
|
75
|
+
The `type` configuration corresponds to either a _Rails_ form helper _ActiveElement_ extension field, i.e. `email_field` will call some variation of:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
form_with do |form|
|
79
|
+
form.email_field :email
|
80
|
+
end
|
81
|
+
```
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Custom Controllers
|
2
|
+
|
3
|
+
The [Default Controller](default-controller.html) provides out-of-the-box functionality to get you up and running quickly, but as your application progresses you will likely need to provide custom functionality in some areas.
|
4
|
+
|
5
|
+
A custom controller is just a regular _Rails_ controller. You can still benefit from default actions provided by _ActiveElement_ and only override the specific actions you need.
|
6
|
+
|
7
|
+
In the example below we'll implement a custom `#show` action on a `UsersController` and create a custom view.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
# app/controllers/users_controller.rb
|
11
|
+
|
12
|
+
class UsersController < ApplicationController
|
13
|
+
active_element.listable_fields :name, :email, :created_at, order: :name
|
14
|
+
active_element.editable_fields :name, :email
|
15
|
+
active_element.searchable_fields :name, :name, :created_at, :updated_at
|
16
|
+
active_element.deletable
|
17
|
+
|
18
|
+
def show
|
19
|
+
@user = User.find(params[:id])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
```
|
23
|
+
|
24
|
+
```erb
|
25
|
+
<%# app/views/users/index.html.erb %>
|
26
|
+
|
27
|
+
<%= active_element.component.page_title 'Users' %>
|
28
|
+
|
29
|
+
<%= active_element.component.table item: @user, fields: [:email, :name, :created_at, :updated_at] %>
|
30
|
+
```
|
31
|
+
|
32
|
+
You can customize any action or view you like, simply by following standard _Rails_ patterns.
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# Default Controller
|
2
|
+
|
3
|
+
The default controller in _ActiveElement_ provides all the standard _Rails_ actions:
|
4
|
+
|
5
|
+
* `#index`
|
6
|
+
* `#show`
|
7
|
+
* `#new`
|
8
|
+
* `#create`
|
9
|
+
* `#edit`
|
10
|
+
* `#update`
|
11
|
+
* `#destroy`
|
12
|
+
|
13
|
+
All controllers that inherit from `ActiveElement::ApplicationController` automatically receive these routes, but they must be explicitly enabled in order to serve content, otherwise a default `403 Forbidden` page will be rendered.
|
14
|
+
|
15
|
+
Each controller expects to find a model whose name corresponds to the controller, in line with typical _Rails_ conventions. For example, if you have a `RestaurantsController` then _ActiveElement_ will expect to find a `Restaurant` model. Each of the declarations covered below describe interactions with a corresponding model.
|
16
|
+
|
17
|
+
Depending on which declarations are defined in your controllers, you will see different _UI_ elements (e.g. a _Delete_ button for each record will only be present when `active_element.deletable` has been called).
|
18
|
+
|
19
|
+
## Associations
|
20
|
+
|
21
|
+
Model associations are supported, so you can list database columns as well as relations defined on your model.
|
22
|
+
|
23
|
+
Here's a basic example:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# app/models/restaurant.rb
|
27
|
+
|
28
|
+
class Restaurant < ApplicationRecord
|
29
|
+
belongs_to :restaurateur
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
# app/models/restaurateur.rb
|
35
|
+
|
36
|
+
class Restaurateur < ApplicationRecord
|
37
|
+
has_many :resaturants
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
# app/controllers/restaurants_controller.rb
|
43
|
+
|
44
|
+
class RestaurantsController < ApplicationController
|
45
|
+
active_element.listable_fields :name, :restaurateur, :created_at
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
Now when you browse to `/restaurants` you'll see a link to each restaurants owner in the rendered table.
|
50
|
+
|
51
|
+
## Listable Fields
|
52
|
+
|
53
|
+
The `active_element.listable_fields` declaration provides a list of fields on your model that should be displayed in the default `#index` view.
|
54
|
+
|
55
|
+
A table of results will be rendered containing each record corresponding for the corresponding record, including _View_, _Edit_, and _Delete_ buttons, as well as a button above the table to create a new record.
|
56
|
+
|
57
|
+
The `order` keyword allows you to sort the results by a given field. This value is passed directly to the `ActiveRecord` `order` method, so you can use `:name` or `{ name: :desc }` or any other variation that `ActiveRecord` accepts.
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# app/controllers/restaurants_controller.rb
|
61
|
+
|
62
|
+
class RestaurantsController < ApplicationController
|
63
|
+
active_element.listable_fields :name, :restaurateur, :created_at, order: :name
|
64
|
+
end
|
65
|
+
```
|
66
|
+
|
67
|
+
As mentioned above, associations are supported, so the `restaurateur` association will automatically map to the associated record and you'll be provided with a link to that record in the results table.
|
68
|
+
|
69
|
+
Pagination is also provided by the default `#index` action.
|
70
|
+
|
71
|
+
## Searchable Fields
|
72
|
+
|
73
|
+
The `active_element.searchable_fields` declaration provides a list of fields on your model that can be searched by a user. You can specify `string`, `integer`, and `datetime` fields.
|
74
|
+
|
75
|
+
A search form is generated and user input is processed according to column type.
|
76
|
+
|
77
|
+
* `string` fields generate an `ILIKE` (case-insensitive `LIKE`) query from user input: `"joh"` will match `"John Smith"`.
|
78
|
+
* `integer` fields require an exact match.
|
79
|
+
* `datetime` fields provide a range, allowing users to provide a start date/time, an end date/time, or both.
|
80
|
+
* Association fields will join on the relevant association and search all `string` and `integer` fields defined in the `searchable_fields` for the controller corresponding to the association model.
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
# app/controllers/restaurants_controller.rb
|
84
|
+
|
85
|
+
class RestaurantsController < ApplicationController
|
86
|
+
active_element.searchable_fields :name, :restaurateur, :created_at
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
# app/controllers/restaurateurs_controller.rb
|
92
|
+
|
93
|
+
class RestaurateursController < ApplicationController
|
94
|
+
active_element.searchable_fields :name, :address
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
## Viewable Fields
|
99
|
+
|
100
|
+
The `active_element.viewable_fields` declaration provides a list of fields on your model that will be included when viewing an individual record via the `#show` action.
|
101
|
+
|
102
|
+
The results will be rendered in a horizontal table with one row for each item, including a _Delete_ and _Edit_ button above the table.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
# app/controllers/restaurants_controller.rb
|
106
|
+
|
107
|
+
class RestaurantsController < ApplicationController
|
108
|
+
active_element.searchable_fields :name, :restaurateur, :created_at
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
## Editable Fields
|
113
|
+
|
114
|
+
The `active_element.editable_fields` declaration provides a list of fields on your model that can be modified by a user.
|
115
|
+
|
116
|
+
This declaration enables both the `#edit`, `#new`, `#update`, and `#create` actions as well as defining the permitted parameters for `#update` and `#create`. A form is automatically generated and each field is selected according to the column data type.
|
117
|
+
|
118
|
+
Note that each field type can be overridden and configured by defining `config/forms/<model>/<field.yml>`, allowing you to make many customizations to each field without having to work with views or override the default controller actions, as well as allowing each field configuration to be re-used in multiple places. See the [Form Fields](components/form-fields.html) documentation for more details.
|
119
|
+
|
120
|
+
By default, `json` and `jsonb` fields use the [JSON Field](form-fields/json.html) type, allowing you to edit complex _JSON_ data structures via user-friendly _HTML_ forms. A [schema file](form-fields/json/schema.html) **must** be defined for these fields. See the `json_field` documentation for more details.
|
121
|
+
|
122
|
+
## Deletable
|
123
|
+
|
124
|
+
The `active_element.deletable` declaration does not receive any arguments but specifies that a record can be deleted by a user.
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
# app/controllers/restaurants_controller.rb
|
128
|
+
|
129
|
+
class RestaurantsController < ApplicationController
|
130
|
+
active_element.deletable
|
131
|
+
end
|
132
|
+
```
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_element
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bob Farrell
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-06-
|
11
|
+
date: 2023-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bootstrap
|
@@ -116,6 +116,7 @@ files:
|
|
116
116
|
- app/assets/javascripts/active_element/application.js
|
117
117
|
- app/assets/javascripts/active_element/confirm.js
|
118
118
|
- app/assets/javascripts/active_element/form.js
|
119
|
+
- app/assets/javascripts/active_element/highlight.js
|
119
120
|
- app/assets/javascripts/active_element/json_field.js
|
120
121
|
- app/assets/javascripts/active_element/pagination.js
|
121
122
|
- app/assets/javascripts/active_element/popover.js
|
@@ -168,6 +169,7 @@ files:
|
|
168
169
|
- app/views/active_element/decorators/_datetime.html.erb
|
169
170
|
- app/views/active_element/decorators/_time.html.erb
|
170
171
|
- app/views/active_element/default_views/edit.html.erb
|
172
|
+
- app/views/active_element/default_views/forbidden.html.erb
|
171
173
|
- app/views/active_element/default_views/index.html.erb
|
172
174
|
- app/views/active_element/default_views/new.html.erb
|
173
175
|
- app/views/active_element/default_views/show.html.erb
|
@@ -186,6 +188,7 @@ files:
|
|
186
188
|
- app/views/layouts/active_element.html.erb
|
187
189
|
- app/views/layouts/active_element_error.html.erb
|
188
190
|
- config/brakeman.ignore
|
191
|
+
- config/locales/en.yml
|
189
192
|
- config/routes.rb
|
190
193
|
- example_app/.gitattributes
|
191
194
|
- example_app/.gitignore
|
@@ -309,13 +312,18 @@ files:
|
|
309
312
|
- lib/active_element/components/util/form_field_mapping.rb
|
310
313
|
- lib/active_element/components/util/form_value_mapping.rb
|
311
314
|
- lib/active_element/components/util/i18n.rb
|
315
|
+
- lib/active_element/components/util/numeric_field.rb
|
312
316
|
- lib/active_element/components/util/record_mapping.rb
|
313
317
|
- lib/active_element/components/util/record_path.rb
|
314
318
|
- lib/active_element/controller_action.rb
|
315
319
|
- lib/active_element/controller_interface.rb
|
320
|
+
- lib/active_element/controller_state.rb
|
316
321
|
- lib/active_element/default_controller.rb
|
317
|
-
- lib/active_element/
|
318
|
-
- lib/active_element/
|
322
|
+
- lib/active_element/default_controller/actions.rb
|
323
|
+
- lib/active_element/default_controller/controller.rb
|
324
|
+
- lib/active_element/default_controller/json_params.rb
|
325
|
+
- lib/active_element/default_controller/params.rb
|
326
|
+
- lib/active_element/default_controller/search.rb
|
319
327
|
- lib/active_element/engine.rb
|
320
328
|
- lib/active_element/json_field_schema.rb
|
321
329
|
- lib/active_element/permissions_check.rb
|
@@ -350,6 +358,8 @@ files:
|
|
350
358
|
- rspec-documentation/pages/010-Components/Tables/Item Table.md
|
351
359
|
- rspec-documentation/pages/010-Components/Tables/Options.md
|
352
360
|
- rspec-documentation/pages/010-Components/Tabs.md
|
361
|
+
- rspec-documentation/pages/015-Custom Controllers.md
|
362
|
+
- rspec-documentation/pages/016-Default Controller.md
|
353
363
|
- rspec-documentation/pages/020-Access Control.md
|
354
364
|
- rspec-documentation/pages/020-Access Control/010-Authentication.md
|
355
365
|
- rspec-documentation/pages/020-Access Control/020-Authorization.md
|
@@ -363,6 +373,7 @@ files:
|
|
363
373
|
- rspec-documentation/pages/040-Decorators/View Decorators.md
|
364
374
|
- rspec-documentation/pages/300-Alternatives.md
|
365
375
|
- rspec-documentation/pages/900-License.md
|
376
|
+
- rspec-documentation/pages/Themes.md
|
366
377
|
- rspec-documentation/spec_helper.rb
|
367
378
|
- rspec-documentation/support.rb
|
368
379
|
- sig/active_element.rbs
|
@@ -1,62 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveElement
|
4
|
-
# Provides params for ActiveRecord models when using the default boilerplate controller
|
5
|
-
# actions. Navigates input parameters and maps them to appropriate relations as needed.
|
6
|
-
class DefaultRecordParams
|
7
|
-
def initialize(controller:, model:)
|
8
|
-
@controller = controller
|
9
|
-
@model = model
|
10
|
-
end
|
11
|
-
|
12
|
-
def params
|
13
|
-
with_transformed_relations(
|
14
|
-
controller.params.require(controller.controller_name.singularize)
|
15
|
-
.permit(controller.active_element.state.fetch(:editable_fields, []))
|
16
|
-
)
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
attr_reader :controller, :model
|
22
|
-
|
23
|
-
def with_transformed_relations(params)
|
24
|
-
params.to_h.to_h do |key, value|
|
25
|
-
next [key, value] unless relation?(key)
|
26
|
-
|
27
|
-
relation_param(key, value)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def relation_param(key, value)
|
32
|
-
case relation(key).macro
|
33
|
-
when :belongs_to
|
34
|
-
belongs_to_param(key, value)
|
35
|
-
when :has_one
|
36
|
-
has_one_param(key, value)
|
37
|
-
when :has_many
|
38
|
-
has_many_param(key, value)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def belongs_to_param(key, value)
|
43
|
-
[relation(key).foreign_key, value]
|
44
|
-
end
|
45
|
-
|
46
|
-
def has_one_param(key, value) # rubocop:disable Naming/PredicateName
|
47
|
-
[relation(key).name, relation(key).klass.find_by(relation(key).klass.primary_key => value)]
|
48
|
-
end
|
49
|
-
|
50
|
-
def has_many_param(key, _value) # rubocop:disable Naming/PredicateName
|
51
|
-
[relation(key).name, relation(key).klass.where(relation(key).klass.primary_key => relation(key).value)]
|
52
|
-
end
|
53
|
-
|
54
|
-
def relation?(attribute)
|
55
|
-
relation(attribute.to_sym).present?
|
56
|
-
end
|
57
|
-
|
58
|
-
def relation(attribute)
|
59
|
-
model.reflect_on_association(attribute.to_sym)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
@@ -1,110 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveElement
|
4
|
-
# Full text search querying for DefaultController, provides full text search filters for all
|
5
|
-
# controllers with configured searchable fields. Includes support for querying across relations.
|
6
|
-
class DefaultTextSearch
|
7
|
-
def initialize(controller:, model:)
|
8
|
-
@controller = controller
|
9
|
-
@model = model
|
10
|
-
end
|
11
|
-
|
12
|
-
def search_filters
|
13
|
-
@search_filters ||= controller.params.permit(*searchable_fields).transform_values do |value|
|
14
|
-
value.try(:compact_blank) || value
|
15
|
-
end.compact_blank
|
16
|
-
end
|
17
|
-
|
18
|
-
def text_search?
|
19
|
-
search_filters.present?
|
20
|
-
end
|
21
|
-
|
22
|
-
def text_search
|
23
|
-
conditions = search_filters.to_h.map do |key, value|
|
24
|
-
next relation_matches(key, value) if relation?(key)
|
25
|
-
next datetime_between(key, value) if datetime?(key)
|
26
|
-
|
27
|
-
model.arel_table[key].matches("#{value}%")
|
28
|
-
end
|
29
|
-
conditions[1..].reduce(conditions.first) do |accumulated, condition|
|
30
|
-
accumulated.and(condition)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def search_relations
|
35
|
-
search_filters.to_h.keys.map { |key| relation?(key) ? key.to_sym : nil }.compact
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
attr_reader :controller, :model
|
41
|
-
|
42
|
-
def searchable_fields
|
43
|
-
base_fields = controller.active_element.state.fetch(:searchable_fields, [])
|
44
|
-
base_fields.map do |field|
|
45
|
-
next field unless field.to_s.end_with?('_at')
|
46
|
-
|
47
|
-
{ field => %i[from to] }
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def noop
|
52
|
-
Arel::Nodes::True.new.eq(Arel::Nodes::True.new)
|
53
|
-
end
|
54
|
-
|
55
|
-
def datetime?(key)
|
56
|
-
model.columns.find { |column| column.name.to_s == key.to_s }&.type == :datetime
|
57
|
-
end
|
58
|
-
|
59
|
-
def datetime_between(key, value)
|
60
|
-
return noop if value[:from].blank? && value[:to].blank?
|
61
|
-
|
62
|
-
model.arel_table[key].between(range_begin(value)...range_end(value))
|
63
|
-
end
|
64
|
-
|
65
|
-
def range_begin(value)
|
66
|
-
value[:from].present? ? Time.zone.parse(value[:from]) + timezone_offset : -Float::INFINITY
|
67
|
-
end
|
68
|
-
|
69
|
-
def range_end
|
70
|
-
value[:to].present? ? Time.zone.parse(value[:to]) + timezone_offset : Float::INFINITY
|
71
|
-
end
|
72
|
-
|
73
|
-
def timezone_offset
|
74
|
-
controller.request.cookies['timezone_offset'].to_i.minutes
|
75
|
-
end
|
76
|
-
|
77
|
-
def relation_matches(key, value)
|
78
|
-
fields = searchable_relation_fields(key)
|
79
|
-
relation_model = relation(key).klass
|
80
|
-
fields.select! do |field|
|
81
|
-
relation_model.columns.find { |column| column.name.to_s == field.to_s }&.type == :string
|
82
|
-
end
|
83
|
-
|
84
|
-
return noop if fields.empty?
|
85
|
-
|
86
|
-
relation_conditions(fields, value, relation_model)
|
87
|
-
end
|
88
|
-
|
89
|
-
def relation_conditions(fields, value, relation_model)
|
90
|
-
fields[1..].reduce(relation_model.arel_table[fields.first].matches("#{value}%")) do |condition, field|
|
91
|
-
condition.or(relation_model.arel_table[field].matches("#{value}%"))
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def searchable_relation_fields(key)
|
96
|
-
Components::Util.relation_controller(model, controller, key)
|
97
|
-
&.active_element
|
98
|
-
&.state
|
99
|
-
&.fetch(:searchable_fields, []) || []
|
100
|
-
end
|
101
|
-
|
102
|
-
def relation?(attribute)
|
103
|
-
relation(attribute.to_sym).present?
|
104
|
-
end
|
105
|
-
|
106
|
-
def relation(attribute)
|
107
|
-
model.reflect_on_association(attribute.to_sym)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|