anchormodel 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/doc/method_list.html CHANGED
@@ -54,23 +54,23 @@
54
54
 
55
55
  <li class="even ">
56
56
  <div class="item">
57
- <span class='object_link'><a href="Anchormodel.html#all-class_method" title="Anchormodel.all (method)">all</a></span>
58
- <small>Anchormodel</small>
57
+ <span class='object_link'><a href="AnchormodelGenerator.html#add_anchormodel-instance_method" title="AnchormodelGenerator#add_anchormodel (method)">#add_anchormodel</a></span>
58
+ <small>AnchormodelGenerator</small>
59
59
  </div>
60
60
  </li>
61
61
 
62
62
 
63
63
  <li class="odd ">
64
64
  <div class="item">
65
- <span class='object_link'><a href="Anchormodel/Attribute.html#anchormodel_class-instance_method" title="Anchormodel::Attribute#anchormodel_class (method)">#anchormodel_class</a></span>
66
- <small>Anchormodel::Attribute</small>
65
+ <span class='object_link'><a href="Anchormodel.html#all-class_method" title="Anchormodel.all (method)">all</a></span>
66
+ <small>Anchormodel</small>
67
67
  </div>
68
68
  </li>
69
69
 
70
70
 
71
71
  <li class="even ">
72
72
  <div class="item">
73
- <span class='object_link'><a href="Anchormodel/Attribute.html#attribute_name-instance_method" title="Anchormodel::Attribute#attribute_name (method)">#attribute_name</a></span>
73
+ <span class='object_link'><a href="Anchormodel/Attribute.html#anchormodel_class-instance_method" title="Anchormodel::Attribute#anchormodel_class (method)">#anchormodel_class</a></span>
74
74
  <small>Anchormodel::Attribute</small>
75
75
  </div>
76
76
  </li>
@@ -78,32 +78,32 @@
78
78
 
79
79
  <li class="odd ">
80
80
  <div class="item">
81
- <span class='object_link'><a href="Anchormodel/ModelMixin.html#belongs_to_anchormodel-class_method" title="Anchormodel::ModelMixin.belongs_to_anchormodel (method)">belongs_to_anchormodel</a></span>
82
- <small>Anchormodel::ModelMixin</small>
81
+ <span class='object_link'><a href="Anchormodel/Attribute.html#attribute_name-instance_method" title="Anchormodel::Attribute#attribute_name (method)">#attribute_name</a></span>
82
+ <small>Anchormodel::Attribute</small>
83
83
  </div>
84
84
  </li>
85
85
 
86
86
 
87
87
  <li class="even ">
88
88
  <div class="item">
89
- <span class='object_link'><a href="Anchormodel/ActiveModelTypeValue.html#cast-instance_method" title="Anchormodel::ActiveModelTypeValue#cast (method)">#cast</a></span>
90
- <small>Anchormodel::ActiveModelTypeValue</small>
89
+ <span class='object_link'><a href="Anchormodel/ModelMixin.html#belongs_to_anchormodel-class_method" title="Anchormodel::ModelMixin.belongs_to_anchormodel (method)">belongs_to_anchormodel</a></span>
90
+ <small>Anchormodel::ModelMixin</small>
91
91
  </div>
92
92
  </li>
93
93
 
94
94
 
95
95
  <li class="odd ">
96
96
  <div class="item">
97
- <span class='object_link'><a href="Anchormodel/ActiveModelTypeValue.html#changed%3F-instance_method" title="Anchormodel::ActiveModelTypeValue#changed? (method)">#changed?</a></span>
98
- <small>Anchormodel::ActiveModelTypeValue</small>
97
+ <span class='object_link'><a href="Anchormodel/ActiveModelTypeValueSingle.html#cast-instance_method" title="Anchormodel::ActiveModelTypeValueSingle#cast (method)">#cast</a></span>
98
+ <small>Anchormodel::ActiveModelTypeValueSingle</small>
99
99
  </div>
100
100
  </li>
101
101
 
102
102
 
103
103
  <li class="even ">
104
104
  <div class="item">
105
- <span class='object_link'><a href="Anchormodel/ActiveModelTypeValue.html#deserialize-instance_method" title="Anchormodel::ActiveModelTypeValue#deserialize (method)">#deserialize</a></span>
106
- <small>Anchormodel::ActiveModelTypeValue</small>
105
+ <span class='object_link'><a href="Anchormodel/ActiveModelTypeValueSingle.html#changed_in_place%3F-instance_method" title="Anchormodel::ActiveModelTypeValueSingle#changed_in_place? (method)">#changed_in_place?</a></span>
106
+ <small>Anchormodel::ActiveModelTypeValueSingle</small>
107
107
  </div>
108
108
  </li>
109
109
 
@@ -142,13 +142,21 @@
142
142
 
143
143
  <li class="odd ">
144
144
  <div class="item">
145
- <span class='object_link'><a href="Anchormodel/ActiveModelTypeValue.html#initialize-instance_method" title="Anchormodel::ActiveModelTypeValue#initialize (method)">#initialize</a></span>
146
- <small>Anchormodel::ActiveModelTypeValue</small>
145
+ <span class='object_link'><a href="Anchormodel/ActiveModelTypeValueSingle.html#initialize-instance_method" title="Anchormodel::ActiveModelTypeValueSingle#initialize (method)">#initialize</a></span>
146
+ <small>Anchormodel::ActiveModelTypeValueSingle</small>
147
147
  </div>
148
148
  </li>
149
149
 
150
150
 
151
151
  <li class="even ">
152
+ <div class="item">
153
+ <span class='object_link'><a href="Anchormodel/SimpleFormInputs/Helpers/AnchormodelInputsCommon.html#input-instance_method" title="Anchormodel::SimpleFormInputs::Helpers::AnchormodelInputsCommon#input (method)">#input</a></span>
154
+ <small>Anchormodel::SimpleFormInputs::Helpers::AnchormodelInputsCommon</small>
155
+ </div>
156
+ </li>
157
+
158
+
159
+ <li class="odd ">
152
160
  <div class="item">
153
161
  <span class='object_link'><a href="Anchormodel.html#inspect-instance_method" title="Anchormodel#inspect (method)">#inspect</a></span>
154
162
  <small>Anchormodel</small>
@@ -156,6 +164,14 @@
156
164
  </li>
157
165
 
158
166
 
167
+ <li class="even ">
168
+ <div class="item">
169
+ <span class='object_link'><a href="Anchormodel/Util.html#install_methods_in_model-class_method" title="Anchormodel::Util.install_methods_in_model (method)">install_methods_in_model</a></span>
170
+ <small>Anchormodel::Util</small>
171
+ </div>
172
+ </li>
173
+
174
+
159
175
  <li class="odd ">
160
176
  <div class="item">
161
177
  <span class='object_link'><a href="Anchormodel.html#key-instance_method" title="Anchormodel#key (method)">#key</a></span>
@@ -182,13 +198,21 @@
182
198
 
183
199
  <li class="even ">
184
200
  <div class="item">
185
- <span class='object_link'><a href="Anchormodel/ActiveModelTypeValue.html#serialize-instance_method" title="Anchormodel::ActiveModelTypeValue#serialize (method)">#serialize</a></span>
186
- <small>Anchormodel::ActiveModelTypeValue</small>
201
+ <span class='object_link'><a href="Anchormodel/ActiveModelTypeValueSingle.html#serializable%3F-instance_method" title="Anchormodel::ActiveModelTypeValueSingle#serializable? (method)">#serializable?</a></span>
202
+ <small>Anchormodel::ActiveModelTypeValueSingle</small>
187
203
  </div>
188
204
  </li>
189
205
 
190
206
 
191
207
  <li class="odd ">
208
+ <div class="item">
209
+ <span class='object_link'><a href="Anchormodel/ActiveModelTypeValueSingle.html#serialize-instance_method" title="Anchormodel::ActiveModelTypeValueSingle#serialize (method)">#serialize</a></span>
210
+ <small>Anchormodel::ActiveModelTypeValueSingle</small>
211
+ </div>
212
+ </li>
213
+
214
+
215
+ <li class="even ">
192
216
  <div class="item">
193
217
  <span class='object_link'><a href="Anchormodel.html#setup!-class_method" title="Anchormodel.setup! (method)">setup!</a></span>
194
218
  <small>Anchormodel</small>
@@ -196,7 +220,7 @@
196
220
  </li>
197
221
 
198
222
 
199
- <li class="even ">
223
+ <li class="odd ">
200
224
  <div class="item">
201
225
  <span class='object_link'><a href="Anchormodel.html#to_s-instance_method" title="Anchormodel#to_s (method)">#to_s</a></span>
202
226
  <small>Anchormodel</small>
@@ -204,6 +228,14 @@
204
228
  </li>
205
229
 
206
230
 
231
+ <li class="even ">
232
+ <div class="item">
233
+ <span class='object_link'><a href="Anchormodel/ActiveModelTypeValueSingle.html#type-instance_method" title="Anchormodel::ActiveModelTypeValueSingle#type (method)">#type</a></span>
234
+ <small>Anchormodel::ActiveModelTypeValueSingle</small>
235
+ </div>
236
+ </li>
237
+
238
+
207
239
 
208
240
  </ul>
209
241
  </div>
@@ -84,7 +84,7 @@
84
84
 
85
85
 
86
86
 
87
- <strong class="classes">Classes:</strong> <span class='object_link'><a href="Anchormodel.html" title="Anchormodel (class)">Anchormodel</a></span>
87
+ <strong class="classes">Classes:</strong> <span class='object_link'><a href="Anchormodel.html" title="Anchormodel (class)">Anchormodel</a></span>, <span class='object_link'><a href="AnchormodelGenerator.html" title="AnchormodelGenerator (class)">AnchormodelGenerator</a></span>, <span class='object_link'><a href="AnchormodelInput.html" title="AnchormodelInput (class)">AnchormodelInput</a></span>, <span class='object_link'><a href="AnchormodelRadioButtonsInput.html" title="AnchormodelRadioButtonsInput (class)">AnchormodelRadioButtonsInput</a></span>
88
88
 
89
89
 
90
90
  </p>
@@ -100,9 +100,9 @@
100
100
  </div>
101
101
 
102
102
  <div id="footer">
103
- Generated on Wed Jan 25 12:36:39 2023 by
103
+ Generated on Wed Apr 24 17:01:46 2024 by
104
104
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
105
- 0.9.28 (ruby-3.1.3).
105
+ 0.9.28 (ruby-3.2.2).
106
106
  </div>
107
107
 
108
108
  </div>
@@ -1,15 +1,22 @@
1
1
  # @see https://www.rubydoc.info/docs/rails/ActiveModel/Type/Value
2
- class Anchormodel::ActiveModelTypeValue < ActiveModel::Type::Value
2
+ class Anchormodel::ActiveModelTypeValueSingle < ActiveModel::Type::Value
3
3
  def initialize(attribute)
4
4
  super()
5
5
  @attribute = attribute
6
6
  end
7
7
 
8
+ def type
9
+ :anchormodel
10
+ end
11
+
12
+ # This converts an Anchormodel instance to string for DB
8
13
  def cast(value)
9
- serialize value
14
+ value = value.presence
15
+ return value if value.is_a?(@attribute.anchormodel_class)
16
+ return @attribute.anchormodel_class.find(value)
10
17
  end
11
18
 
12
- # Implementing this instead of cast to force key validation in any case
19
+ # This converts DB or input to an Anchormodel instance
13
20
  def serialize(value)
14
21
  value = value.presence
15
22
  return case value
@@ -27,13 +34,19 @@ class Anchormodel::ActiveModelTypeValue < ActiveModel::Type::Value
27
34
  end
28
35
  end
29
36
 
30
- def deserialize(value)
31
- value = value.presence
32
- return value if value.is_a?(@attribute.anchormodel_class)
33
- return @attribute.anchormodel_class.find(value)
37
+ def serializable?(value)
38
+ return case value
39
+ when Symbol, String
40
+ @attribute.anchormodel_class.valid_keys.exclude?(value.to_sym)
41
+ when nil, @attribute.anchormodel_class
42
+ true
43
+ else
44
+ false
45
+ end
34
46
  end
35
47
 
36
- def changed?(old_value, new_value, _new_value_before_type_cast)
37
- return deserialize(old_value) != deserialize(new_value)
48
+ def changed_in_place?(raw_old_value, value)
49
+ old_value = deserialize(raw_old_value)
50
+ old_value != value
38
51
  end
39
52
  end
@@ -9,88 +9,10 @@ module Anchormodel::ModelMixin
9
9
 
10
10
  class_methods do
11
11
  # Creates an attribute linking to an Anchormodel. The attribute should be
12
- # present in the DB and the column should be named the same as `attribute_name.`
13
- # @param attribute_name [String,Symbol] The name and database column of the attribute
14
- # @param anchormodel_class [Class] Class of the Anchormodel (omit if attribute `:foo_bar` holds a `FooBar`)
15
- # @param optional [Boolean] If true, a presence validation is added to the model.
16
- # @param model_readers [Boolean] If true, the model is given an ActiveRecord::Enum style method `my_model.my_key?` reader for each key in the anchormodel
17
- # @param model_writers [Boolean] If true, the model is given an ActiveRecord::Enum style method `my_model.my_key!` writer for each key in the anchormodel
18
- # @param model_scopes [Boolean] If true, the model is given an ActiveRecord::Enum style scope `MyModel.mykey` for each key in the anchormodel
19
- # @param model_methods [Boolean, NilClass] If non-nil, this mass-assigns and overrides `model_readers`, `model_writers` and `model_scopes`
20
- def belongs_to_anchormodel(attribute_name, anchormodel_class = nil, optional: false, model_readers: true,
21
- model_writers: true, model_scopes: true, model_methods: nil)
22
- anchormodel_class ||= attribute_name.to_s.classify.constantize
23
- attribute_name = attribute_name.to_sym
24
- attribute = Anchormodel::Attribute.new(self, attribute_name, anchormodel_class, optional)
25
-
26
- # Mass configurations if model_methods was specfied
27
- unless model_methods.nil?
28
- model_readers = model_methods
29
- model_writers = model_methods
30
- model_scopes = model_methods
31
- end
32
-
33
- # Register attribute
34
- self.anchormodel_attributes = anchormodel_attributes.merge({ attribute_name => attribute }).freeze
35
-
36
- # Add presence validation if required
37
- unless optional
38
- validates attribute_name, presence: true
39
- end
40
-
41
- # Make casting work
42
- # Define serializer/deserializer
43
- active_model_type_value = Anchormodel::ActiveModelTypeValue.new(attribute)
44
-
45
- # Overwrite reader to force building anchors at every retrieval
46
- define_method(attribute_name.to_s) do
47
- active_model_type_value.deserialize(read_attribute(attribute_name))
48
- end
49
-
50
- # Override writer to fail early when an invalid target value is specified
51
- define_method("#{attribute_name}=") do |new_value|
52
- write_attribute(attribute_name, active_model_type_value.serialize(new_value))
53
- end
54
-
55
- # Supply serializer and deserializer
56
- attribute attribute_name, active_model_type_value
57
-
58
- # Create ActiveRecord::Enum style reader directly in the model if asked to do so
59
- # For a model User with anchormodel Role with keys :admin and :guest, this creates user.admin? and user.guest? (returning true iff role is admin/guest)
60
- if model_readers
61
- anchormodel_class.all.each do |entry|
62
- if respond_to?(:"#{entry.key}?")
63
- fail("Anchormodel reader #{entry.key}? already defined for #{self}, add `model_readers: false` to `belongs_to_anchormodel :#{attribute_name}`.")
64
- end
65
- define_method(:"#{entry.key}?") do
66
- public_send(attribute_name.to_s) == entry
67
- end
68
- end
69
- end
70
-
71
- # Create ActiveRecord::Enum style writer directly in the model if asked to do so
72
- # For a model User with anchormodel Role with keys :admin and :guest, this creates user.admin! and user.guest! (setting the role to admin/guest)
73
- if model_writers
74
- anchormodel_class.all.each do |entry|
75
- if respond_to?(:"#{entry.key}!")
76
- fail("Anchormodel writer #{entry.key}! already defined for #{self}, add `model_writers: false` to `belongs_to_anchormodel :#{attribute_name}`.")
77
- end
78
- define_method(:"#{entry.key}!") do
79
- public_send(:"#{attribute_name}=", entry)
80
- end
81
- end
82
- end
83
-
84
- # Create ActiveRecord::Enum style scope directly in the model class if asked to do so
85
- # For a model User with anchormodel Role with keys :admin and :guest, this creates user.admin! and user.guest! (setting the role to admin/guest)
86
- if model_scopes
87
- anchormodel_class.all.each do |entry|
88
- if respond_to?(entry.key)
89
- fail("Anchormodel scope #{entry.key} already defined for #{self}, add `model_scopes: false` to `belongs_to_anchormodel :#{attribute_name}`.")
90
- end
91
- scope(entry.key, -> { where(attribute_name => entry.key) })
92
- end
93
- end
12
+ # present in the DB and the column should be of type String and named the same as `attribute_name`.
13
+ # @see Anchormodel::Util#install_methods_in_model Parameters
14
+ def belongs_to_anchormodel(*args, **kwargs)
15
+ Anchormodel::Util.install_methods_in_model(self, *args, **kwargs)
94
16
  end
95
17
  end
96
18
  end
@@ -0,0 +1,21 @@
1
+ unless defined? SimpleForm
2
+ begin
3
+ require 'simple_form'
4
+ rescue LoadError
5
+ nil
6
+ end
7
+
8
+ end
9
+ if defined? SimpleForm
10
+ class AnchormodelInput < SimpleForm::Inputs::CollectionSelectInput
11
+ include Anchormodel::SimpleFormInputs::Helpers::AnchormodelInputsCommon
12
+
13
+ private
14
+
15
+ def sf_selection_key
16
+ :selected
17
+ end
18
+
19
+ def before_render_input; end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ unless defined? SimpleForm
2
+ begin
3
+ require 'simple_form'
4
+ rescue LoadError
5
+ nil
6
+ end
7
+
8
+ end
9
+ if defined? SimpleForm
10
+ class AnchormodelRadioButtonsInput < SimpleForm::Inputs::CollectionRadioButtonsInput
11
+ include Anchormodel::SimpleFormInputs::Helpers::AnchormodelInputsCommon
12
+
13
+ private
14
+
15
+ def sf_selection_key
16
+ :checked
17
+ end
18
+
19
+ def before_render_input
20
+ @input_type = :radio_buttons
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,49 @@
1
+ class Anchormodel
2
+ module SimpleFormInputs
3
+ module Helpers
4
+ module AnchormodelInputsCommon
5
+ def input(wrapper_options = nil)
6
+ unless object.respond_to?(:anchormodel_attributes)
7
+ fail("The form field object does not appear to respond to `anchormodel_attributes`, \
8
+ did you `include Anchormodel::ModelMixin` in your `application_record.rb`? Affected object: #{object.inspect}")
9
+ end
10
+
11
+ am_attr = object.anchormodel_attributes[@attribute_name]
12
+ unless am_attr
13
+ fail("#{@attribute_name.inspect} does not look like an Anchormodel attribute, is `belongs_to_anchormodel` called in your model? \
14
+ Affected object: #{object.inspect}")
15
+ end
16
+ am_class = am_attr.anchormodel_class
17
+
18
+ # Attempt to read selected key from html input options "value", as the caller might not know that this is a select.
19
+ selected_key = input_options[:value]
20
+ if selected_key.blank? && object
21
+ # No selected key override present and a model is present, use the model to find out what to select.
22
+ selected_am = object.send(@attribute_name)
23
+ selected_key = selected_am&.key || am_class.all.first
24
+ end
25
+
26
+ options.deep_merge!(
27
+ label_method: :first,
28
+ value_method: :second,
29
+ sf_selection_key => selected_key.to_s,
30
+ include_blank: am_attr.optional
31
+ )
32
+
33
+ @collection = collect(am_class.all)
34
+
35
+ before_render_input
36
+
37
+ super
38
+ end
39
+
40
+ private
41
+
42
+ # Takes an array of objects implementing the methods `label` and `key` and returns an array suitable for simple_form select fields.
43
+ def collect(flat_array)
44
+ return flat_array.map { |entry| [entry.label, entry.key] }
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,93 @@
1
+ # @api description
2
+ # A swiss army knife for common functionality
3
+ module Anchormodel::Util
4
+ # Installs an anchormodel attribute in a model class
5
+ # @param model_class [ActiveRecord::Base] Internal only. The model class that the attribute should be installed to.
6
+ # @param attribute_name [String,Symbol] The name and database column of the attribute
7
+ # @param anchormodel_class [Class] Class of the Anchormodel (omit if attribute `:foo_bar` holds a `FooBar`)
8
+ # @param optional [Boolean] If false, a presence validation is added to the model.
9
+ # @param model_readers [Boolean] If true, the model is given an ActiveRecord::Enum style method `my_model.my_key?` reader for each key in the anchormodel
10
+ # @param model_writers [Boolean] If true, the model is given an ActiveRecord::Enum style method `my_model.my_key!` writer for each key in the anchormodel
11
+ # @param model_scopes [Boolean] If true, the model is given an ActiveRecord::Enum style scope `MyModel.mykey` for each key in the anchormodel
12
+ # @param model_methods [Boolean, NilClass] If non-nil, this mass-assigns and overrides `model_readers`, `model_writers` and `model_scopes`
13
+ def self.install_methods_in_model(model_class, attribute_name, anchormodel_class = nil,
14
+ optional: false,
15
+ model_readers: true,
16
+ model_writers: true,
17
+ model_scopes: true,
18
+ model_methods: nil)
19
+
20
+ anchormodel_class ||= attribute_name.to_s.classify.constantize
21
+ attribute_name = attribute_name.to_sym
22
+ attribute = Anchormodel::Attribute.new(self, attribute_name, anchormodel_class, optional)
23
+
24
+ # Mass configurations if model_methods was specfied
25
+ unless model_methods.nil?
26
+ model_readers = model_methods
27
+ model_writers = model_methods
28
+ model_scopes = model_methods
29
+ end
30
+
31
+ # Register attribute
32
+ model_class.anchormodel_attributes = model_class.anchormodel_attributes.merge({ attribute_name => attribute }).freeze
33
+
34
+ # Add presence validation if required
35
+ unless optional
36
+ model_class.validates attribute_name, presence: true
37
+ end
38
+
39
+ # Make casting work
40
+ # Define serializer/deserializer
41
+ active_model_type_value = Anchormodel::ActiveModelTypeValueSingle.new(attribute)
42
+
43
+ # Overwrite reader to force building anchors at every retrieval
44
+ model_class.define_method(attribute_name.to_s) do
45
+ active_model_type_value.deserialize(read_attribute_before_type_cast(attribute_name))
46
+ end
47
+
48
+ # Override writer to fail early when an invalid target value is specified
49
+ model_class.define_method("#{attribute_name}=") do |new_value|
50
+ write_attribute(attribute_name, active_model_type_value.serialize(new_value))
51
+ end
52
+
53
+ # Supply serializer and deserializer
54
+ model_class.attribute attribute_name, active_model_type_value
55
+
56
+ # Create ActiveRecord::Enum style reader directly in the model if asked to do so
57
+ # For a model User with anchormodel Role with keys :admin and :guest, this creates user.admin? and user.guest? (returning true iff role is admin/guest)
58
+ if model_readers
59
+ anchormodel_class.all.each do |entry|
60
+ if model_class.respond_to?(:"#{entry.key}?")
61
+ fail("Anchormodel reader #{entry.key}? already defined for #{self}, add `model_readers: false` to `belongs_to_anchormodel :#{attribute_name}`.")
62
+ end
63
+ model_class.define_method(:"#{entry.key}?") do
64
+ public_send(attribute_name.to_s) == entry
65
+ end
66
+ end
67
+ end
68
+
69
+ # Create ActiveRecord::Enum style writer directly in the model if asked to do so
70
+ # For a model User with anchormodel Role with keys :admin and :guest, this creates user.admin! and user.guest! (setting the role to admin/guest)
71
+ if model_writers
72
+ anchormodel_class.all.each do |entry|
73
+ if model_class.respond_to?(:"#{entry.key}!")
74
+ fail("Anchormodel writer #{entry.key}! already defined for #{self}, add `model_writers: false` to `belongs_to_anchormodel :#{attribute_name}`.")
75
+ end
76
+ model_class.define_method(:"#{entry.key}!") do
77
+ public_send(:"#{attribute_name}=", entry)
78
+ end
79
+ end
80
+ end
81
+
82
+ # Create ActiveRecord::Enum style scope directly in the model class if asked to do so
83
+ # For a model User with anchormodel Role with keys :admin and :guest, this creates user.admin! and user.guest! (setting the role to admin/guest)
84
+ if model_scopes
85
+ anchormodel_class.all.each do |entry|
86
+ if model_class.respond_to?(entry.key)
87
+ fail("Anchormodel scope #{entry.key} already defined for #{self}, add `model_scopes: false` to `belongs_to_anchormodel :#{attribute_name}`.")
88
+ end
89
+ model_class.scope(entry.key, -> { where(attribute_name => entry.key) })
90
+ end
91
+ end
92
+ end
93
+ end
@@ -1,11 +1,5 @@
1
1
  class Anchormodel
2
2
  module Version
3
- MAJOR = 0
4
- MINOR = 1
5
- PATCH = 3
6
-
7
- EDGE = false
8
-
9
- LABEL = [MAJOR, MINOR, PATCH, EDGE ? 'edge' : nil].compact.join('.')
3
+ LABEL = (Pathname.new(__FILE__).dirname.dirname.dirname / 'VERSION').read
10
4
  end
11
5
  end
data/lib/anchormodel.rb CHANGED
@@ -77,7 +77,11 @@ class Anchormodel
77
77
  end
78
78
  end
79
79
 
80
- require 'anchormodel/active_model_type_value'
80
+ require 'anchormodel/util'
81
+ require 'anchormodel/active_model_type_value_single'
81
82
  require 'anchormodel/attribute'
82
83
  require 'anchormodel/model_mixin'
83
84
  require 'anchormodel/version'
85
+ require 'anchormodel/simple_form_inputs/helpers/anchormodel_inputs_common'
86
+ require 'anchormodel/simple_form_inputs/anchormodel_input'
87
+ require 'anchormodel/simple_form_inputs/anchormodel_radio_buttons_input'
@@ -118,4 +118,23 @@ class UserTest < Minitest::Test
118
118
  u.secondary_role = ''
119
119
  assert_nil u.secondary_role
120
120
  end
121
+
122
+ # Attempting to create a model with an invalid constant name should fail
123
+ def test_invalid_key_update
124
+ assert_raises(RuntimeError) { User.create!(role: :admin, locale: :de, preferred_locale: :invalid) }
125
+ end
126
+
127
+ # Attempting to assign an invalid constant name to a model should fail
128
+ def test_invalid_key_assignment
129
+ assert_raises(RuntimeError) { User.new(role: :invalid) }
130
+ end
131
+
132
+ # An invalid constant name into the DB should raise when reading
133
+ def test_invalid_db_read
134
+ sql = <<~SQL.squish
135
+ INSERT INTO users (role, locale, preferred_locale, created_at, updated_at) VALUES ('invalid', 'de', 'de', 'now', 'now')
136
+ SQL
137
+ ActiveRecord::Base.connection.execute(sql)
138
+ assert_raises(RuntimeError) { User.first.role }
139
+ end
121
140
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anchormodel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sandro Kalbermatter
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-19 00:00:00.000000000 Z
11
+ date: 2024-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -150,8 +150,8 @@ dependencies:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
152
  version: 1.6.0
153
- description:
154
- email:
153
+ description:
154
+ email:
155
155
  executables: []
156
156
  extensions: []
157
157
  extra_rdoc_files: []
@@ -165,13 +165,17 @@ files:
165
165
  - LICENSE
166
166
  - README.md
167
167
  - Rakefile
168
+ - VERSION
168
169
  - anchormodel.gemspec
169
170
  - bin/rails
170
171
  - doc/Anchormodel.html
171
172
  - doc/Anchormodel/ActiveModelTypeValue.html
173
+ - doc/Anchormodel/ActiveModelTypeValueSingle.html
172
174
  - doc/Anchormodel/Attribute.html
173
175
  - doc/Anchormodel/ModelMixin.html
176
+ - doc/Anchormodel/Util.html
174
177
  - doc/Anchormodel/Version.html
178
+ - doc/AnchormodelGenerator.html
175
179
  - doc/_index.html
176
180
  - doc/class_list.html
177
181
  - doc/css/common.css
@@ -187,9 +191,13 @@ files:
187
191
  - doc/method_list.html
188
192
  - doc/top-level-namespace.html
189
193
  - lib/anchormodel.rb
190
- - lib/anchormodel/active_model_type_value.rb
194
+ - lib/anchormodel/active_model_type_value_single.rb
191
195
  - lib/anchormodel/attribute.rb
192
196
  - lib/anchormodel/model_mixin.rb
197
+ - lib/anchormodel/simple_form_inputs/anchormodel_input.rb
198
+ - lib/anchormodel/simple_form_inputs/anchormodel_radio_buttons_input.rb
199
+ - lib/anchormodel/simple_form_inputs/helpers/anchormodel_inputs_common.rb
200
+ - lib/anchormodel/util.rb
193
201
  - lib/anchormodel/version.rb
194
202
  - lib/generators/anchormodel/USAGE
195
203
  - lib/generators/anchormodel/anchormodel_generator.rb
@@ -233,7 +241,7 @@ homepage: https://github.com/kalsan/anchormodel
233
241
  licenses:
234
242
  - LGPL-3.0-or-later
235
243
  metadata: {}
236
- post_install_message:
244
+ post_install_message:
237
245
  rdoc_options: []
238
246
  require_paths:
239
247
  - lib
@@ -248,8 +256,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
248
256
  - !ruby/object:Gem::Version
249
257
  version: '0'
250
258
  requirements: []
251
- rubygems_version: 3.4.13
252
- signing_key:
259
+ rubygems_version: 3.5.9
260
+ signing_key:
253
261
  specification_version: 4
254
262
  summary: Bringing object-oriented programming to Rails enums
255
263
  test_files: []