ar_doc_store 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +53 -31
- data/lib/ar_doc_store/embeddable_model.rb +2 -5
- data/lib/ar_doc_store/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 26475c142ad4190f755c67790ee452549a04625c
|
4
|
+
data.tar.gz: 50df0fd6be02fc56a5ade3af39ad8faf0946b212
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57894eff1ed254c21e932e4b18df91f2d1cf2d0e7c5f7496b2bf0866909456f97c2679aa00657ddc5d85b9768de9944e7bfe256b82e470d133c9267635207ee6
|
7
|
+
data.tar.gz: 9523be413ae72a83b3f58826509018acc3bd43f2269eba15b78b2b247e374021f32b698c3173cb07fd7965c0321c22e2e0fc044f43e8484d60fb649fc790bafc
|
data/README.md
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
# ArDocStore
|
2
2
|
|
3
|
-
ArDocStore is a gem
|
3
|
+
ArDocStore (pronounced R-Dock-Store) is a gem helps you implement a document store in ActiveRecord models that have access to the PostgreSQL JSON data type. You add a json column to your table called "data", include the ArDocStore::Model module, and then add schema-less attributes that get stored in the data column. With Ransack, these attributes are searchable as if they were real columns.
|
4
4
|
|
5
5
|
There is also support for embedding models within models. These embedded models can be accessed from Rails form builders using fields_for.
|
6
6
|
|
7
7
|
The use case is primarily when you have a rapidly evolving schema with scores of attributes, where you would like to use composition but don't want to have a bajillion tables for data that fits squarely under the umbrella of its parent entity. For example, a building has entrances and restrooms, and the entrance and restroom each have a door and a route to the door. You could have active record models for the doors, routes, restrooms, and entrances, but you know that you only ever need to access the bathroom door from within the context of the building's bathroom. You don't need to access all the doors as their own entities because their existence is entirely contingent upon the entity within which they are contained. ArDocStore makes this easy.
|
8
8
|
|
9
|
+
Learn more about the JSON column in Postgres and using it as a document store:
|
10
|
+
* The Rails Guide on Postgres: http://edgeguides.rubyonrails.org/active_record_postgresql.html
|
11
|
+
* Document Store Gymnastics: http://rob.conery.io/2015/03/01/document-storage-gymnastics-in-postgres/
|
12
|
+
* PG as NoSQL: http://thebuild.com%5Cpresentations%5Cpg-as-nosql-pgday-fosdem-2013.pdf
|
13
|
+
* Why JSON in PostgreSQL is Awesome: https://functionwhatwhat.com/json-in-postgresql/
|
14
|
+
* Indexing JSONB: http://michael.otacoo.com/postgresql-2/postgres-9-4-feature-highlight-indexing-jsonb/
|
15
|
+
|
16
|
+
|
9
17
|
## Installation
|
10
18
|
|
11
19
|
Add this line to your application's Gemfile:
|
@@ -24,11 +32,11 @@ Or install it yourself as:
|
|
24
32
|
|
25
33
|
## Usage
|
26
34
|
|
27
|
-
The first thing you need to do is create a migration that adds a column called "data" of type ":json" to the table you want to turn into a document:
|
35
|
+
The first thing you need to do is create a migration that adds a column called "data" of type ":json" or ":jsonb" to the table you want to turn into a document:
|
28
36
|
|
29
37
|
```ruby
|
30
38
|
change_table :buildings do |t|
|
31
|
-
|
39
|
+
t.jsonb :data
|
32
40
|
end
|
33
41
|
```
|
34
42
|
|
@@ -36,7 +44,7 @@ Then in the model file:
|
|
36
44
|
|
37
45
|
```ruby
|
38
46
|
class Building < ActiveRecord::Base
|
39
|
-
|
47
|
+
include ArDocStore::Model
|
40
48
|
end
|
41
49
|
```
|
42
50
|
|
@@ -45,14 +53,17 @@ end
|
|
45
53
|
Now there are several ways to play but all boil down to one method on the model:
|
46
54
|
```ruby
|
47
55
|
class Building < ActiveRecord::Base
|
48
|
-
|
56
|
+
include ArDocStore::Model
|
49
57
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
58
|
+
attribute :name, :string
|
59
|
+
attribute :width, :float
|
60
|
+
attribute :height, as: :float # the :as is optional but if you like the consistency with SimpleForm
|
61
|
+
attribute :storeys, :integer
|
62
|
+
attribute :finished, :boolean
|
63
|
+
attribute :construction_type, :enumeration,
|
64
|
+
values: %w{wood plaster mud brick},
|
65
|
+
multiple: true,
|
66
|
+
strict: true
|
56
67
|
end
|
57
68
|
```
|
58
69
|
|
@@ -69,7 +80,11 @@ You noticed the enumeration type on the construction_type takes an array. That's
|
|
69
80
|
|
70
81
|
```ruby
|
71
82
|
class Building ...
|
72
|
-
|
83
|
+
attribute :construction_type,
|
84
|
+
:enumeration,
|
85
|
+
values: %w{wood plaster mud brick},
|
86
|
+
multiple: true,
|
87
|
+
strict: true
|
73
88
|
end
|
74
89
|
building = Building.new
|
75
90
|
building.construction_type = 'wood'
|
@@ -86,9 +101,17 @@ Let's say that a building has a door. The building is not the only thing in our
|
|
86
101
|
class Door
|
87
102
|
include ArDocStore::EmbeddableModel
|
88
103
|
|
89
|
-
enumerates :door_type,
|
90
|
-
|
91
|
-
|
104
|
+
enumerates :door_type,
|
105
|
+
multiple: true,
|
106
|
+
values: %w{single double french sliding push pull}
|
107
|
+
attribute :open_handle,
|
108
|
+
as: :enumeration,
|
109
|
+
multiple: true,
|
110
|
+
values: %w{push pull plate knob handle}
|
111
|
+
attribute :close_handle,
|
112
|
+
as: :enumeration,
|
113
|
+
multiple: true,
|
114
|
+
values: %w{push pull plate knob handle}
|
92
115
|
attribute :clear_distance, as: :integer
|
93
116
|
attribute :opening_force, as: :integer
|
94
117
|
attribute :clear_space, as: :integer
|
@@ -129,11 +152,11 @@ end
|
|
129
152
|
|
130
153
|
# in the view, with a bonus plug for Slim templates:
|
131
154
|
= simple_form_for @building do |form|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
155
|
+
= form.input :name, as: :string
|
156
|
+
= form.input :height, as: :float
|
157
|
+
= form.object.ensure_door
|
158
|
+
= form.fields_for :door do |door_form|
|
159
|
+
= door_form.input :door_type, as: :check_boxes, collection: Door.door_type_choices
|
137
160
|
```
|
138
161
|
|
139
162
|
What's to see here? Notice that I was able to "ensure_door", which means that if there already is a door, it keeps that one, otherwise it builds a new door object. Also on the door_type input, notice the collection comes from a door_type_choices that came from the enumeration attribute. Also notice that the embedded model conforms to the API for accepts_nested_attributes, for both assignment and validation, only you don't have to specify it because the _attributes= method comes for free.
|
@@ -142,16 +165,16 @@ You can also embeds_many. It works the same way:
|
|
142
165
|
|
143
166
|
```ruby
|
144
167
|
class Room
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
168
|
+
include ArDocStore::EmbeddableModel
|
169
|
+
attribute :length, as: :float
|
170
|
+
attribute :width, as: :float
|
171
|
+
attribute :height, as: :float
|
172
|
+
enumerates :light_switch_type, %w{flip knob switchplate clapper}
|
150
173
|
end
|
151
174
|
|
152
175
|
class Building ...
|
153
|
-
|
154
|
-
|
176
|
+
embeds_many :rooms
|
177
|
+
embeds_one :foyer, class_name: 'Room'
|
155
178
|
end
|
156
179
|
|
157
180
|
building = Building.new
|
@@ -227,10 +250,9 @@ end
|
|
227
250
|
```
|
228
251
|
|
229
252
|
## Roadmap
|
230
|
-
1.
|
231
|
-
2.
|
232
|
-
3.
|
233
|
-
4. Migration support to rename attributes, remove attributes. (I haven't needed yet...)
|
253
|
+
1. Ransackers for embedded model attributes. Deliberately left out because when you have nested JSON, Postgres searches on any keys within the JSON become 10x slower.
|
254
|
+
2. It would be nice if you could use the AR fluent query API on stored attributes, where is knows to replace, say, "name" with "data->>name" but I don't see how to do that, and Ransack provides a nice enough wrapper around ARel to get the job done another way.
|
255
|
+
3. Migration support to rename attributes, remove attributes. (Right now just query the documents you need to change, iterate and update the JSON directly.)
|
234
256
|
|
235
257
|
## Contributing
|
236
258
|
|
@@ -1,9 +1,6 @@
|
|
1
1
|
module ArDocStore
|
2
|
-
|
3
2
|
module EmbeddableModel
|
4
|
-
|
5
3
|
def self.included(mod)
|
6
|
-
|
7
4
|
mod.send :include, ActiveModel::AttributeMethods
|
8
5
|
mod.send :include, ActiveModel::Validations
|
9
6
|
mod.send :include, ActiveModel::Conversion
|
@@ -13,7 +10,7 @@ module ArDocStore
|
|
13
10
|
mod.send :include, ArDocStore::Storage
|
14
11
|
mod.send :include, ArDocStore::Embedding
|
15
12
|
mod.send :include, InstanceMethods
|
16
|
-
mod.send :extend,
|
13
|
+
mod.send :extend, ClassMethods
|
17
14
|
|
18
15
|
mod.class_eval do
|
19
16
|
attr_accessor :_destroy
|
@@ -89,7 +86,7 @@ module ArDocStore
|
|
89
86
|
#:nodoc:
|
90
87
|
def store_accessor(store, key)
|
91
88
|
self.virtual_attributes ||= HashWithIndifferentAccess.new
|
92
|
-
virtual_attributes
|
89
|
+
self.virtual_attributes = virtual_attributes.merge key => true
|
93
90
|
key = key.to_sym
|
94
91
|
define_method key, -> { read_store_attribute(:data, key) }
|
95
92
|
define_method "#{key}=".to_sym, -> (value) { write_store_attribute :data, key, value }
|
data/lib/ar_doc_store/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ar_doc_store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Furber
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|