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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 401138e35802b70caf47d7ee217637e2dd7ff4f3
4
- data.tar.gz: f2bd57d5d211506a6150f377f0b5d4955badd513
3
+ metadata.gz: 26475c142ad4190f755c67790ee452549a04625c
4
+ data.tar.gz: 50df0fd6be02fc56a5ade3af39ad8faf0946b212
5
5
  SHA512:
6
- metadata.gz: 5d75e45318b4863bf94a2e40ed2925f13ccd98ddf5c5ef901e77e7570f3c0fe6bfd73dab1fdb8292a11ea48a2e60b11d8db561ddc0010a7bbc7b530daec55df2
7
- data.tar.gz: c296bf89a1288ae64269e5c478d8caa684b0df4dd9f0272e67fad841ae91baa02a582e286c7b6882a7e4991c61909e7834f9e2e2a8b9128e7c5b1847d16d2a19
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 that makes it easy to handle document-store like behavior 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.
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
- t.json :data
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
- include ArDocStore::Model
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
- include ArDocStore::Model
56
+ include ArDocStore::Model
49
57
 
50
- attribute :name, :string
51
- attribute :width, :float
52
- attribute :height, as: :float # the :as is optional but if you like the consistency with SimpleForm
53
- attribute :storeys, :integer
54
- attribute :finished, :boolean
55
- attribute :construction_type, :enumeration, values: %w{wood plaster mud brick}, multiple: true, strict: true
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
- attribute :construction_type, :enumeration, values: %w{wood plaster mud brick}, multiple: true, strict: true
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, multiple: true, values: %w{single double french sliding push pull}
90
- attribute :open_handle, as: :enumeration, multiple: true, values: %w{push pull plate knob handle}
91
- attribute :close_handle, as: :enumeration, multiple: true, values: %w{push pull plate knob handle}
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
- = form.input :name, as: :string
133
- = form.input :height, as: :float
134
- = form.object.ensure_door
135
- = form.fields_for :door do |door_form|
136
- = door_form.input :door_type, as: :check_boxes, collection: Door.door_type_choices
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
- include ArDocStore::EmbeddableModel
146
- attribute :length, as: :float
147
- attribute :width, as: :float
148
- attribute :height, as: :float
149
- enumerates :light_switch_type, %w{flip knob switchplate clapper}
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
- embeds_many :rooms
154
- embeds_one :foyer, class_name: 'Room'
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. Default values for attributes. (I haven't needed yet...)
231
- 2. Ransackers for embedded model attributes. (I haven't needed yet, but may this summer when the inspiring project goes to phase 2...)
232
- 3. 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.
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, ClassMethods
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[key] ||= true
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 }
@@ -1,3 +1,3 @@
1
1
  module ArDocStore
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
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.2
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-13 00:00:00.000000000 Z
11
+ date: 2015-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord