active_element 0.0.18 → 0.0.20

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c6d9d2e62cd64334ba324d02116adda1fb4177b3ada32e2634c69ddc8a59d42
4
- data.tar.gz: d37225180b3932060de9cbbaa4d1e5c69a70ccf277aeaaa27fdd94a99b2327f9
3
+ metadata.gz: 667ecfa2f26f661d4c0f760529fdc4ae944e242fdefecba10d6cc5b194b1e822
4
+ data.tar.gz: 28f0326bb18b3bf7fb402a5b89e82c796621825779fdaa2a754817e5028fe8e0
5
5
  SHA512:
6
- metadata.gz: 6f97e214aa565b0c47bcac56a11340a043ecf5f0d138229e9827f7a35f730cc66d44e0ce73666c8f7fe87126a30beb0fe06e8a16072eadcb4cf264fe579762f5
7
- data.tar.gz: d30d2534b1418c8f9ad70dcca84b7a53587d5e171d7c9b8489d51667c4714f502de905382d7ec030566da90eb02f8c2141f76a888f7a52770b4a711fbf6576b7
6
+ metadata.gz: 1d7a79658f6ec7d58e2aac0492fe952d7df2c6d4873f2a4ad9390735b3f5c868947bb9722c92ec4bb640bf2909c3ad064e3ecaf7fccd5c07992810d9ee3344ee
7
+ data.tar.gz: d48338e4f22be093bf6b3c6ef3ca2acce3150a3db3fde1b715408b4f8de3ce41f2c6a3074982b4426fc53de6f5609b5de443f8192c5b602008f37abe1cbf0621
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- active_element (0.0.18)
4
+ active_element (0.0.20)
5
5
  bootstrap (~> 5.3.0alpha3)
6
6
  kaminari (~> 1.2)
7
7
  paintbrush (~> 0.1.2)
@@ -83,7 +83,7 @@ GEM
83
83
  autoprefixer-rails (10.4.16.0)
84
84
  execjs (~> 2)
85
85
  bcrypt (3.1.18)
86
- bootstrap (5.3.2)
86
+ bootstrap (5.3.3)
87
87
  autoprefixer-rails (>= 9.1.0)
88
88
  popper_js (>= 2.11.8, < 3)
89
89
  brakeman (5.4.1)
@@ -145,21 +145,21 @@ GEM
145
145
  net-imap
146
146
  net-pop
147
147
  net-smtp
148
- marcel (1.0.2)
148
+ marcel (1.0.4)
149
149
  method_source (1.0.0)
150
150
  mini_mime (1.1.5)
151
151
  mini_portile2 (2.8.2)
152
152
  minitest (5.18.1)
153
- net-imap (0.4.10)
153
+ net-imap (0.4.11)
154
154
  date
155
155
  net-protocol
156
156
  net-pop (0.1.2)
157
157
  net-protocol
158
158
  net-protocol (0.2.2)
159
159
  timeout
160
- net-smtp (0.4.0.1)
160
+ net-smtp (0.5.0)
161
161
  net-protocol
162
- nio4r (2.7.0)
162
+ nio4r (2.7.3)
163
163
  nokogiri (1.15.2)
164
164
  mini_portile2 (~> 2.8.2)
165
165
  racc (~> 1.4)
data/README.md CHANGED
@@ -1,31 +1,5 @@
1
1
  # ActiveElement
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ ActiveElement is a framework for building admin applications in Rails.
4
4
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/active_element`. To experiment with that code, run `bin/console` for an interactive prompt.
6
-
7
- ## Installation
8
-
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
10
-
11
- Install the gem and add to the application's Gemfile by executing:
12
-
13
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
14
-
15
- If bundler is not being used to manage dependencies, install the gem by executing:
16
-
17
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
18
-
19
- ## Usage
20
-
21
- TODO: Write usage instructions here
22
-
23
- ## Development
24
-
25
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
26
-
27
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
28
-
29
- ## Contributing
30
-
31
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/active_element.
5
+ See the [documentation](https://docs.bob.frl/active_element) to get started.
@@ -27,8 +27,8 @@ module ActiveElement
27
27
  helper_method :active_element
28
28
  helper_method :render_active_element_hook
29
29
 
30
- def render_active_element_hook(hook)
31
- render_to_string partial: hook
30
+ def render_active_element_hook(hook, locals: {})
31
+ render_to_string partial: hook, locals: locals
32
32
  rescue ActionView::MissingTemplate
33
33
  nil
34
34
  end
@@ -6,7 +6,7 @@
6
6
  'bs-trigger': 'hover',
7
7
  'bs-toggle': 'popover',
8
8
  'bs-content': title,
9
- } : {}),
9
+ } : {}).merge(method&.to_s == 'get' ? {} : { 'turbo-method' => method.to_s }),
10
10
  class: "btn #{button_class} #{float_class} #{kwargs_class}",
11
11
  **kwargs
12
12
  ) do %>
@@ -59,13 +59,23 @@
59
59
  <% fields.each_slice(columns) do |field_group| %>
60
60
  <div class="row form-fields mb-3">
61
61
  <% field_group.each do |field, type, options| %>
62
- <div class="col-sm-3">
63
- <%= render partial: 'active_element/components/form/label',
64
- locals: { component: component, id: id, type: type, form: form, field: field, options: options } %>
65
- </div>
62
+ <% if type != :hidden_field %>
63
+ <div class="col-sm-3">
64
+ <%= render partial: 'active_element/components/form/label',
65
+ locals: {
66
+ component: component,
67
+ id: id,
68
+ type: type,
69
+ form: form,
70
+ field: field,
71
+ options: options
72
+ } %>
73
+ </div>
74
+ <% end %>
66
75
 
67
76
 
68
- <div class="col">
77
+
78
+ <% if type != :hidden_field %><div class="col"><% end %>
69
79
  <%= render partial: 'active_element/components/form/field',
70
80
  locals: {
71
81
  id: id,
@@ -76,7 +86,7 @@
76
86
  component: component,
77
87
  record: record }
78
88
  %>
79
- </div>
89
+ <% if type != :hidden_field %></div><% end %>
80
90
  <% end %>
81
91
  </div>
82
92
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <tr class="<%= (index % 2).zero? ? 'even' : 'odd' %> <%= row_class_mapper.call(item) %>">
2
2
  <% fields.each do |field, class_mapper, label, value_mapper| %>
3
- <td class="align-middle <%= class_mapper.call(item) %>">
3
+ <td class="align-top <%= class_mapper.call(item) %>">
4
4
  <% if component.secret_field?(field) %>
5
5
  <%= controller.helpers.render partial: 'active_element/components/secret/field',
6
6
  locals: { secret: value_mapper.call(item), label: label } %>
@@ -1,5 +1,10 @@
1
1
  <% if new %>
2
- <%= active_element.component.new_button(component.model&.new, float: 'end', class: 'mb-3') %>
2
+ <%= active_element.component.new_button(
3
+ component.model&.new,
4
+ nested_for: nested_for,
5
+ float: 'end',
6
+ class: 'mb-3'
7
+ ) %>
3
8
  <% end %>
4
9
 
5
10
 
@@ -1,9 +1,9 @@
1
1
  <%= active_element.component.page_title record.model_name.to_s.titleize %>
2
2
 
3
- <%= render_active_element_hook "#{controller_path}/before_edit" %>
3
+ <%= render_active_element_hook "#{controller_path}/before_edit", locals: { record: record } %>
4
4
 
5
5
  <%= active_element.component.form model: [namespace, record].compact,
6
6
  destroy: active_element.state.deletable?,
7
7
  fields: active_element.state.editable_fields %>
8
8
 
9
- <%= render_active_element_hook "#{controller_path}/after_edit" %>
9
+ <%= render_active_element_hook "#{controller_path}/after_edit", locals: { record: record } %>
@@ -7,7 +7,17 @@
7
7
  fields: active_element.state.searchable_fields %>
8
8
  <% end %>
9
9
 
10
- <%= render_active_element_hook "#{controller_path}/before_index" %>
10
+ <%= render_active_element_hook "#{controller_path}/before_index", locals: { collection: collection } %>
11
+
12
+ <% if nested_for.present? %>
13
+ <%=
14
+ active_element.component.page_section_title(
15
+ nested_for.map do |nested_for_record|
16
+ ActiveElement::Components::Util::DefaultDisplayValue.new(object: nested_for_record).value
17
+ end.join(', ')
18
+ )
19
+ %>
20
+ <% end %>
11
21
 
12
22
  <% if active_element.state.search_required && search_filters.compact_blank.blank? %>
13
23
  <% if active_element.state.creatable? %>
@@ -20,8 +30,9 @@
20
30
  show: active_element.state.viewable?,
21
31
  edit: active_element.state.editable?,
22
32
  destroy: active_element.state.deletable?,
33
+ nested_for: nested_for,
23
34
  collection: collection,
24
35
  fields: active_element.state.listable_fields %>
25
36
  <% end %>
26
37
 
27
- <%= render_active_element_hook "#{controller_path}/after_index" %>
38
+ <%= render_active_element_hook "#{controller_path}/after_index", locals: { collection: collection } %>
@@ -1,10 +1,10 @@
1
1
  <%= active_element.component.page_title record.model_name.to_s.titleize %>
2
2
 
3
- <%= render_active_element_hook "#{controller_path}/before_show" %>
3
+ <%= render_active_element_hook "#{controller_path}/before_show", locals: { record: record } %>
4
4
 
5
5
  <%= active_element.component.table item: record,
6
6
  edit: active_element.state.editable?,
7
7
  destroy: active_element.state.deletable?,
8
8
  fields: active_element.state.viewable_fields %>
9
9
 
10
- <%= render_active_element_hook "#{controller_path}/after_show" %>
10
+ <%= render_active_element_hook "#{controller_path}/after_show", locals: { record: record } %>
@@ -19,6 +19,15 @@
19
19
  </script>
20
20
  <% end %>
21
21
 
22
+ <% if respond_to?(:javascript_pack_tag) && defined? Webpacker %>
23
+ <%= begin
24
+ javascript_pack_tag 'application'
25
+ rescue Webpacker::Manifest::MissingEntryError
26
+ nil
27
+ end
28
+ %>
29
+ <% end %>
30
+
22
31
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
23
32
  <link rel="stylesheet"
24
33
  href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/default.min.css">
@@ -116,6 +125,5 @@
116
125
  <%= javascript_include_tag 'active_element/active_element', 'data-turbo-track': 'reload', 'data-turbolinks-track': 'reload' %>
117
126
  <%= javascript_include_tag 'application', 'data-turbo-track': 'reload', 'data-turbolinks-track': 'reload' %>
118
127
  <% end %>
119
-
120
128
  </body>
121
129
  </html>
data/config/routes.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  ActiveElement::Engine.routes.draw do
4
4
  ActiveElement.eager_load_controllers
5
+ ActiveElement.eager_load_models
5
6
 
6
7
  ActiveElement::ApplicationController.descendants.map do |descendant|
7
8
  post "#{descendant.controller_path}/_active_element_text_search",
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- active_element (0.0.14)
4
+ active_element (0.0.18)
5
5
  bootstrap (~> 5.3.0alpha3)
6
6
  kaminari (~> 1.2)
7
7
  paintbrush (~> 0.1.2)
@@ -6,7 +6,7 @@ module ActiveElement
6
6
  class Button
7
7
  # rubocop:disable Metrics/MethodLength
8
8
  def initialize(controller, record, flag_or_options, confirm: false, type: :primary, method: nil,
9
- float: nil, icon: nil, tooltip: false, **kwargs, &block)
9
+ float: nil, icon: nil, tooltip: false, nested_for: nil, **kwargs, &block)
10
10
  @controller = controller
11
11
  @record = record.is_a?(ActiveRecord::Relation) ? record.klass.new : record
12
12
  @flag_or_options = flag_or_options
@@ -20,6 +20,7 @@ module ActiveElement
20
20
  @block_given = block_given?
21
21
  @content = block.call if block_given?
22
22
  @tooltip = tooltip
23
+ @nested_for = nested_for
23
24
  end
24
25
  # rubocop:enable Metrics/MethodLength
25
26
 
@@ -49,7 +50,7 @@ module ActiveElement
49
50
  private
50
51
 
51
52
  attr_reader :controller, :record, :flag_or_options, :float, :kwargs, :kwargs_class, :type, :method, :icon,
52
- :block_given, :content, :confirm, :tooltip
53
+ :block_given, :content, :confirm, :tooltip, :nested_for
53
54
 
54
55
  def link_method
55
56
  return method if method.present?
@@ -116,7 +117,21 @@ module ActiveElement
116
117
  def record_path
117
118
  return nil unless record.class.is_a?(ActiveModel::Naming)
118
119
 
119
- Util::RecordPath.new(record: record, controller: controller, type: type).path
120
+ Util::RecordPath.new(record: record, controller: controller, type: type).path(**nested_args)
121
+ end
122
+
123
+ def nested_args
124
+ case type
125
+ when :new
126
+ nested_params
127
+ else
128
+ {}
129
+ end
130
+ end
131
+
132
+ def nested_params
133
+ route = controller.request.routes.recognize_path(controller.request.path)
134
+ route.reject { |key, _value| %w[controller action].include?(key.to_s) }
120
135
  end
121
136
  end
122
137
  end
@@ -15,7 +15,7 @@ module ActiveElement
15
15
  # rubocop:disable Metrics/MethodLength
16
16
  def initialize(controller, class_name:, collection:, fields:, params:, model_name: nil, style: nil,
17
17
  show: false, new: false, edit: false, destroy: false, paginate: true, group: nil,
18
- group_title: false, row_class: nil, title: nil, **_kwargs)
18
+ group_title: false, nested_for: nil, row_class: nil, title: nil, **_kwargs)
19
19
  @controller = controller
20
20
  @class_name = class_name
21
21
  @model_name = model_name
@@ -32,6 +32,7 @@ module ActiveElement
32
32
  @group_title = group_title
33
33
  @row_class = row_class
34
34
  @title = title
35
+ @nested_for = nested_for
35
36
  verify_paginate_and_group
36
37
  end
37
38
  # rubocop:enable Metrics/MethodLength
@@ -54,6 +55,7 @@ module ActiveElement
54
55
  destroy: destroy,
55
56
  group: group,
56
57
  group_title: group_title,
58
+ nested_for: nested_for,
57
59
  display_pagination: display_pagination?,
58
60
  page_sizes: [5, 10, 25, 50, 75, 100, 200],
59
61
  page_size: page_size,
@@ -78,7 +80,7 @@ module ActiveElement
78
80
 
79
81
  attr_reader :class_name, :collection, :fields, :style, :row_class,
80
82
  :new, :show, :edit, :destroy,
81
- :paginate, :params, :group, :group_title, :title
83
+ :paginate, :params, :group, :group_title, :title, :nested_for
82
84
 
83
85
  def paginated_collection
84
86
  return collection unless paginate && collection.respond_to?(:page) && !limit?
@@ -190,14 +190,30 @@ module ActiveElement
190
190
  end
191
191
 
192
192
  def base_options_for_select(field, field_options)
193
- return normalized_options(field_options.fetch(:options)) if field_options.key?(:options)
193
+ return normalized_options(field_options.fetch(:options), field_options) if field_options.key?(:options)
194
194
  return default_options_for_select(field, field_options) if record.class.is_a?(ActiveModel::Naming)
195
195
 
196
196
  raise ArgumentError, "Must provide select options `[:#{field}, { options: [...] }]` or a record instance."
197
197
  end
198
198
 
199
- def normalized_options(options)
200
- options.map { |option| option.is_a?(Array) ? option : [option, option] }
199
+ def normalized_options(options, field_options)
200
+ options.map do |option|
201
+ next option if option.is_a?(Array)
202
+ next active_record_option(option, field_options) if option.is_a?(ActiveRecord::Base)
203
+ [option, option] if option.is_a?(String)
204
+ end
205
+ end
206
+
207
+ def active_record_option(option, field_options)
208
+ [active_record_display_value(option, field_options), option.send(option.class.primary_key)]
209
+ end
210
+
211
+ def active_record_display_value(option, field_options)
212
+ if field_options[:display_value].is_a?(Proc) && record.present?
213
+ field_options[:display_value].call(option)
214
+ else
215
+ Util::DefaultDisplayValue.new(object: option).value
216
+ end
201
217
  end
202
218
 
203
219
  def default_class_name
@@ -12,6 +12,10 @@ module ActiveElement
12
12
  end
13
13
 
14
14
  def value
15
+ if object.respond_to?(:default_display_attribute)
16
+ return object.public_send(object.default_display_attribute)
17
+ end
18
+
15
19
  DEFAULT_FIELDS.each do |field|
16
20
  return object.public_send(field) if active_record_value?(field)
17
21
  return object[field] if hash_key(field) if hash_value?(field)
@@ -59,10 +59,12 @@ module ActiveElement
59
59
  end
60
60
 
61
61
  def inline_configured_field(field)
62
- field_options = FieldOptions.from_state(field, controller.active_element.state, record)
62
+ field_options = FieldOptions.from_state(
63
+ field, controller.active_element.state, record, controller
64
+ )
63
65
  return nil if field_options.blank?
64
66
 
65
- [field, field_options.type, field_options.options]
67
+ [field, field_options.type, field_options.options.reverse_merge({ value: field_options.value })]
66
68
  end
67
69
 
68
70
  def field_with_provided_type_and_provided_options(field)
@@ -201,6 +203,7 @@ module ActiveElement
201
203
  json: :json_field,
202
204
  jsonb: :json_field,
203
205
  geometry: :text_area,
206
+ text: :text_area,
204
207
  datetime: :datetime_field,
205
208
  date: :date_field,
206
209
  time: :time_field,
@@ -80,13 +80,22 @@ module ActiveElement
80
80
  end
81
81
 
82
82
  def value_from_config
83
- field_options = FieldOptions.from_state(field, component.controller.active_element.state, record)
83
+ field_options = field_options_from_state
84
84
  return nil if field_options.blank?
85
85
  return nil unless DATABASE_TYPES.include?(field_options.type.to_sym)
86
86
 
87
87
  send("#{field_options.type}_value")
88
88
  end
89
89
 
90
+ def field_options_from_state
91
+ FieldOptions.from_state(
92
+ field,
93
+ component.controller.active_element.state,
94
+ record,
95
+ component.controller
96
+ )
97
+ end
98
+
90
99
  # Override these methods as required in a class that includes this module:
91
100
 
92
101
  def mapped_association_from_record
@@ -25,8 +25,9 @@ module ActiveElement
25
25
  @authorize
26
26
  end
27
27
 
28
- def listable_fields(*args, order: nil)
28
+ def listable_fields(*args, order: nil, scope: nil)
29
29
  state.list_order = order
30
+ state.list_scope = scope
30
31
  state.listable_fields.concat(args.map(&:to_sym)).uniq!
31
32
  end
32
33
 
@@ -8,7 +8,7 @@ module ActiveElement
8
8
  attr_reader :permissions, :listable_fields, :viewable_fields, :editable_fields, :searchable_fields,
9
9
  :field_options
10
10
  attr_accessor :sign_in_path, :sign_in, :sign_in_method, :sign_out_path, :sign_out_method,
11
- :deletable, :authorizor, :authenticator, :list_order, :search_required, :model
11
+ :deletable, :authorizor, :authenticator, :list_order, :list_scope, :search_required, :model
12
12
 
13
13
  def initialize(controller:)
14
14
  @controller = controller
@@ -15,7 +15,8 @@ module ActiveElement
15
15
  controller.render 'active_element/default_views/index',
16
16
  locals: {
17
17
  collection: ordered(collection),
18
- search_filters: default_text_search.search_filters
18
+ search_filters: default_text_search.search_filters,
19
+ nested_for: nested_relations
19
20
  }
20
21
  end
21
22
 
@@ -124,9 +125,12 @@ module ActiveElement
124
125
  end
125
126
 
126
127
  def collection
127
- return model.all unless default_text_search.text_search?
128
+ return model.public_send(list_scope).where(nested_scope) unless default_text_search.text_search?
128
129
 
129
- model.left_outer_joins(default_text_search.search_relations).where(*default_text_search.text_search)
130
+ model.public_send(list_scope)
131
+ .left_outer_joins(default_text_search.search_relations)
132
+ .where(nested_scope)
133
+ .where(*default_text_search.text_search)
130
134
  end
131
135
 
132
136
  def render_range_error(error:, action:)
@@ -140,6 +144,36 @@ module ActiveElement
140
144
 
141
145
  I18n.t('active_element.unexpected_error')
142
146
  end
147
+
148
+ def list_scope
149
+ return :all if state.list_scope.blank?
150
+ return state.list_scope.call(request) if state.list_scope.is_a?(Proc)
151
+
152
+ state.list_scope
153
+ end
154
+
155
+ def nested_scope
156
+ nested_params.presence || noop
157
+ end
158
+
159
+ def noop
160
+ Arel::Nodes::True.new.eq(Arel::Nodes::True.new)
161
+ end
162
+
163
+ def nested_params
164
+ route = controller.request.routes.recognize_path(controller.request.path)
165
+ route.reject { |key, _value| %w[controller action].include?(key.to_s) }
166
+ end
167
+
168
+ def nested_relations
169
+ return [] if nested_params.blank?
170
+
171
+ nested_params.map do |key, value|
172
+ collection.model.reflections.values.find do |reflection|
173
+ reflection.foreign_key.to_s == key.to_s
174
+ end&.klass&.find(value)
175
+ end.compact
176
+ end
143
177
  end
144
178
  end
145
179
  end
@@ -25,6 +25,7 @@ module ActiveElement
25
25
  conditions = search_filters.to_h.map do |key, value|
26
26
  next relation_matches(key, value) if relation?(key)
27
27
  next datetime_between(key, value) if datetime?(key)
28
+ next join(key, value) if key.to_s.include?('.')
28
29
  next model.arel_table[key].matches("#{value}%") if string_like_column?(key)
29
30
 
30
31
  model.arel_table[key].eq(value)
@@ -36,7 +37,15 @@ module ActiveElement
36
37
  end
37
38
 
38
39
  def search_relations
39
- search_filters.to_h.keys.map { |key| relation?(key) ? key.to_sym : nil }.compact
40
+ relation_joins = search_filters.to_h.keys.map { |key| relation?(key) ? key.to_sym : nil }.compact
41
+ (relation_joins + shorthand_joins).uniq
42
+ end
43
+
44
+ def shorthand_joins
45
+ search_filters.to_h
46
+ .keys
47
+ .select { |key| key.to_s.include?('.') }
48
+ .map { |key| key.partition('.').first.to_sym }
40
49
  end
41
50
 
42
51
  private
@@ -66,6 +75,11 @@ module ActiveElement
66
75
  end.compact
67
76
  end
68
77
 
78
+ def join(key, value)
79
+ table, _, column = key.to_s.partition('.')
80
+ relation(table).klass.arel_table[column].eq(value)
81
+ end
82
+
69
83
  def noop
70
84
  Arel::Nodes::True.new.eq(Arel::Nodes::True.new)
71
85
  end
@@ -1,14 +1,14 @@
1
1
  module ActiveElement
2
2
  class FieldOptions
3
- attr_accessor :type, :options
3
+ attr_accessor :type, :options, :value
4
4
  attr_reader :field
5
5
 
6
- def self.from_state(field, state, record)
6
+ def self.from_state(field, state, record, controller)
7
7
  block = state.field_options[field]
8
8
  return nil if block.blank?
9
9
 
10
10
  field_options = new(field)
11
- block.call(field_options, record)
11
+ block.call(field_options, record, controller)
12
12
  field_options
13
13
  end
14
14
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveElement
4
- VERSION = '0.0.18'
4
+ VERSION = '0.0.20'
5
5
  end
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.18
4
+ version: 0.0.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Farrell
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-12 00:00:00.000000000 Z
11
+ date: 2024-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bootstrap