Skip to content

Commit 448bd1b

Browse files
committed
Add Active Record adapter documentation
1 parent 120e36b commit 448bd1b

File tree

1 file changed

+113
-3
lines changed

1 file changed

+113
-3
lines changed

README.md

Lines changed: 113 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,116 @@ Measured::Weight.new("3.14", "kg").format(with_conversion_string: false)
158158
> "3.14 kg"
159159
```
160160

161+
### Active Record
162+
163+
This gem also provides an Active Record adapter for persisting and retrieving measurements with their units, and model validations.
164+
165+
Columns are expected to have the `_value` and `_unit` suffix, and be `DECIMAL` and `VARCHAR`, and defaults are accepted. Customizing the column used to hold units is supported, see below for details.
166+
167+
```ruby
168+
class AddWeightAndLengthToThings < ActiveRecord::Migration
169+
def change
170+
add_column :things, :minimum_weight_value, :decimal, precision: 10, scale: 2
171+
add_column :things, :minimum_weight_unit, :string, limit: 12
172+
173+
add_column :things, :total_length_value, :decimal, precision: 10, scale: 2, default: 0
174+
add_column :things, :total_length_unit, :string, limit: 12, default: "cm"
175+
end
176+
end
177+
```
178+
179+
A column can be declared as a measurement with its measurement subclass:
180+
181+
```ruby
182+
class Thing < ActiveRecord::Base
183+
measured Measured::Weight, :minimum_weight
184+
measured Measured::Length, :total_length
185+
measured Measured::Volume, :total_volume
186+
end
187+
```
188+
189+
You can optionally customize the model's unit column by specifying it in the `unit_field_name` option, as follows:
190+
191+
```ruby
192+
class ThingWithCustomUnitAccessor < ActiveRecord::Base
193+
measured_length :length, :width, :height, unit_field_name: :size_unit
194+
measured_weight :total_weight, :extra_weight, unit_field_name: :weight_unit
195+
measured_volume :total_volume, :extra_volume, unit_field_name: :volume_unit
196+
end
197+
```
198+
199+
Similarly, you can optionally customize the model's value column by specifying it in the `value_field_name` option, as follows:
200+
201+
```ruby
202+
class ThingWithCustomValueAccessor < ActiveRecord::Base
203+
measured_length :length, value_field_name: :custom_length
204+
measured_weight :total_weight, value_field_name: :custom_weight
205+
measured_volume :volume, value_field_name: :custom_volume
206+
end
207+
```
208+
209+
There are some simpler methods for predefined types:
210+
211+
```ruby
212+
class Thing < ActiveRecord::Base
213+
measured_weight :minimum_weight
214+
measured_length :total_length
215+
measured_volume :total_volume
216+
end
217+
```
218+
219+
This will allow you to access and assign a measurement object:
220+
221+
```ruby
222+
thing = Thing.new
223+
thing.minimum_weight = Measured::Weight.new(10, "g")
224+
thing.minimum_weight_unit # "g"
225+
thing.minimum_weight_value # 10
226+
```
227+
228+
Order of assignment does not matter, and each property can be assigned separately and with mass assignment:
229+
230+
```ruby
231+
params = { total_length_unit: "cm", total_length_value: "3" }
232+
thing = Thing.new(params)
233+
thing.total_length.to_s # 3 cm
234+
```
235+
236+
### Validations
237+
238+
Validations are available:
239+
240+
```ruby
241+
class Thing < ActiveRecord::Base
242+
measured_length :total_length
243+
244+
validates :total_length, measured: true
245+
end
246+
```
247+
248+
This will validate that the unit is defined on the measurement, and that there is a value.
249+
250+
Rather than `true` the validation can accept a hash with the following options:
251+
252+
* `message`: Override the default "is invalid" message.
253+
* `units`: A subset of units available for this measurement. Units must be in existing measurement.
254+
* `greater_than`
255+
* `greater_than_or_equal_to`
256+
* `equal_to`
257+
* `less_than`
258+
* `less_than_or_equal_to`
259+
260+
All comparison validations require `Measured::Measurable` values, not scalars. Most of these options replace the `numericality` validator which compares the measurement/method name/proc to the column's value. Validations can also be combined with `presence` validator.
261+
262+
**Note:** Validations are strongly recommended since assigning an invalid unit will cause the measurement to return `nil`, even if there is a value:
263+
264+
```ruby
265+
thing = Thing.new
266+
thing.total_length_value = 1
267+
thing.total_length_unit = "invalid"
268+
thing.total_length # nil
269+
```
270+
161271
## Units and conversions
162272

163273
### SI units support
@@ -269,7 +379,7 @@ Existing alternatives which were considered:
269379
* **Cons**
270380
* Opens up and modifies `Array`, `Date`, `Fixnum`, `Math`, `Numeric`, `String`, `Time`, and `Object`, then depends on those changes internally.
271381
* Lots of code to solve a relatively simple problem.
272-
* No ActiveRecord adapter.
382+
* No Active Record adapter.
273383

274384
### Gem: [quantified](https://github.com/Shopify/quantified)
275385
* **Pros**
@@ -278,7 +388,7 @@ Existing alternatives which were considered:
278388
* All math done with floats making it highly lossy.
279389
* All units assumed to be pluralized, meaning using unit abbreviations is not possible.
280390
* Not actively maintained.
281-
* No ActiveRecord adapter.
391+
* No Active Record adapter.
282392

283393
### Gem: [unitwise](https://github.com/joshwlewis/unitwise)
284394
* **Pros**
@@ -287,7 +397,7 @@ Existing alternatives which were considered:
287397
* **Cons**
288398
* Lots of code. Good code, but lots of it.
289399
* Many modifications to core types.
290-
* ActiveRecord adapter exists but is written and maintained by a different person/org.
400+
* Active Record adapter exists but is written and maintained by a different person/org.
291401
* Not actively maintained.
292402

293403
## Contributing

0 commit comments

Comments
 (0)