has_metadata 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e2f29c8739a41a97beed0ed3c6b331f8ba3cc2da4ee8bacbd7dc269a0113d23a
4
+ data.tar.gz: 9ceb1f806883a0a42a8734270801b88f715357fb8315f8dbf51566d84a4caaad
5
+ SHA512:
6
+ metadata.gz: 91d5b70471591f8c37c8ae7d6849e370356b6f0fb42c324b7e5a451c0b3448564060f178be7c1ec853f53d4302f8eb2acd7ad1f0d13270fd69bd4ac0a19dfc57
7
+ data.tar.gz: a53e2493826bd95af4c129a6fa3b4a73acfee451f1b70797d48fa4803242662d54bda4324b7627204a90718fbc2db65edec46efb60f8fa13d7d38a1ef1ee4736
data/README.md ADDED
@@ -0,0 +1,117 @@
1
+ > ⚠️ **DEPRECATED:** `has_metadata` is no longer maintained. Superseded by
2
+ > [`has_metadata_column`](https://github.com/RISCfuture/has_metadata_column)
3
+ > (also deprecated). No active maintenance. The final release is v1.6.2.
4
+
5
+ has_metadata
6
+ ============
7
+
8
+ **Keep your tables narrow**
9
+
10
+ | | |
11
+ |:------------|:--------------------------------|
12
+ | **Author** | Tim Morgan |
13
+ | **Version** | 1.6.1 (Jan 24, 2012) |
14
+ | **License** | Released under the MIT License. |
15
+
16
+ About
17
+ -----
18
+
19
+ Wide tables are a problem for big databases. If your `ActiveRecord` models have
20
+ 10, maybe 15 columns, some of which are `VARCHARs` or maybe even `TEXTs`, it's
21
+ going to slow your queries down when you start to scale up.
22
+
23
+ The easy solution to this problem is to limit your projections; in other words,
24
+ to only `SELECT` the columns that you actually need. If you've got a `users`
25
+ table with a giant `about_me` text column, and you're only trying to look up the
26
+ user's login, then just select the `login` column.
27
+
28
+ In the long run, though, a superior solution is to just move those
29
+ `about_me`-type columns to a completely different table. This table has just one
30
+ JSON-serialized field, making it schemaless, so it doesn't waste space. Each row
31
+ in this table is associated with a record in another table (`Metadata` `has_one`
32
+ of your models).
33
+
34
+ This way, when your website gets huge, all of your giant, freeform data is in
35
+ one table that you can shard, or move off to an alternate database, or even a
36
+ NoSQL-type document store, or otherwise manage as you please. Your relational
37
+ tables remain slim and efficient, containing only columns that a) are indexed,
38
+ or b) you need frequent access to.
39
+
40
+ This gem includes a generator that creates the `Metadata` model, and a module
41
+ that you can include in your models to define which fields have been spun off to
42
+ the metadata record.
43
+
44
+ Installation
45
+ ------------
46
+
47
+ **Important Note:** This gem is only compatible with Ruby 1.9+ and Rails 3.0+.
48
+
49
+ Firstly, add the gem to your Rails project's `Gemfile`:
50
+
51
+ ```` ruby
52
+ gem 'has_metadata'
53
+ ````
54
+
55
+ Next, run the generator, which will add the `Metadata` model and its migration
56
+ to your application.
57
+
58
+ ```` sh
59
+ rails generate metadata
60
+ ````
61
+
62
+ Usage
63
+ -----
64
+
65
+ The first thing to think about is what columns to keep in your model. You will
66
+ need to keep any indexed columns, or any columns you perform lookups or other
67
+ SQL queries with. You should also keep any frequently accessed columns,
68
+ especially if they are small (integers or booleans). Good candidates for the
69
+ metadata table are the `TEXT`- and `VARCHAR`-type columns that you only need to
70
+ render a page or two in your app.
71
+
72
+ You'll need to change your model's schema so that it has a `metadata_id` column
73
+ that will associate the model with its `Metadata` instance:
74
+
75
+ ```` ruby
76
+ t.belongs_to :metadata
77
+ ````
78
+
79
+ Next, include the `HasMetadata` module in your model, and call the
80
+ `has_metadata` method to define the schema of your metadata. You can get more
81
+ information in the {HasMetadata::ClassMethods#has_metadata} documentation, but for starters, here's a
82
+ basic example:
83
+
84
+ ```` ruby
85
+ class User < ActiveRecord::Base
86
+ include HasMetadata
87
+ has_metadata({
88
+ about_me: { type: String, length: { maximum: 512 } },
89
+ birthdate: { type: Date, presence: true },
90
+ zipcode: { type: Number, numericality: { greater_than: 9999, less_than: 10_000} }
91
+ })
92
+ end
93
+ ````
94
+
95
+ As you can see, you pass field names mapped to a hash. The hash describes the
96
+ validation that will be performed, and is in the same format as a call to
97
+ `validates`. In addition to the `EachValidator` keys shown above, you can also
98
+ pass a `type` key, to constrain the Ruby type that can be assigned to the field.
99
+
100
+ Each of these fields (in this case, `about_me`, `birthdate`, and `zipcode`) can
101
+ be accessed and set as first_level methods on an instance of your model:
102
+
103
+ ```` ruby
104
+ user.about_me #=> "I was born in 1982 in Aberdeen. My father was a carpenter from..."
105
+ ````
106
+
107
+ ... and thus, used as part of `form_for` fields:
108
+
109
+ ```` ruby
110
+ form_for user do |f|
111
+ f.text_area :about_me, rows: 5, cols: 80
112
+ end
113
+ ````
114
+
115
+ The only thing you _can't_ do is use these fields in a query, obviously. You
116
+ can't do something like `User.where(zipcode: 90210)`, because that column
117
+ doesn't exist on the `users` table.
data/has_metadata.gemspec CHANGED
@@ -2,23 +2,24 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
+ # stub: has_metadata 1.6.2 ruby lib
5
6
 
6
7
  Gem::Specification.new do |s|
7
8
  s.name = "has_metadata"
8
- s.version = "1.6.0"
9
+ s.version = "1.6.2"
9
10
 
10
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
12
  s.authors = ["Tim Morgan"]
12
- s.date = "2012-01-24"
13
+ s.date = "2013-12-08"
13
14
  s.description = "has_metadata lets you move non-indexed and weighty columns off of your big tables by creating a separate metadata table to store all this extra information. Works with Ruby 1.9. and Rails 3.0."
14
15
  s.email = "git@timothymorgan.info"
15
16
  s.extra_rdoc_files = [
16
17
  "LICENSE",
17
- "README.textile"
18
+ "README.md"
18
19
  ]
19
20
  s.files = [
20
21
  "LICENSE",
21
- "README.textile",
22
+ "README.md",
22
23
  "has_metadata.gemspec",
23
24
  "lib/has_metadata.rb",
24
25
  "lib/has_metadata/metadata_generator.rb",
@@ -29,11 +30,20 @@ Gem::Specification.new do |s|
29
30
  s.homepage = "http://github.com/riscfuture/has_metadata"
30
31
  s.require_paths = ["lib"]
31
32
  s.required_ruby_version = Gem::Requirement.new(">= 1.9")
32
- s.rubygems_version = "1.8.15"
33
- s.summary = "Reduce your table width by moving non-indexed columns to a separate metadata table"
33
+ s.rubygems_version = "2.1.11"
34
+ s.summary = "[DEPRECATED] Reduce your table width by moving non-indexed columns to a separate metadata table"
35
+ s.post_install_message = <<~MSG
36
+
37
+ ⚠️ DEPRECATED: has_metadata is no longer maintained.
38
+
39
+ Superseded by `has_metadata_column` (also deprecated as of this notice). No active maintenance.
40
+
41
+ This is the final release. No further updates are planned.
42
+
43
+ MSG
34
44
 
35
45
  if s.respond_to? :specification_version then
36
- s.specification_version = 3
46
+ s.specification_version = 4
37
47
 
38
48
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
39
49
  s.add_runtime_dependency(%q<rails>, [">= 3.2"])
@@ -5,19 +5,19 @@ require 'rails/generators/migration'
5
5
  # @private
6
6
  class MetadataGenerator < Rails::Generators::Base
7
7
  include Rails::Generators::Migration
8
-
8
+
9
9
  source_root "#{File.dirname __FILE__}/../../templates"
10
-
10
+
11
11
  def self.next_migration_number(dirname)
12
12
  if ActiveRecord::Base.timestamped_migrations then
13
- Time.now.utc.strftime "%Y%m%d%H%M%S"
13
+ Time.now.utc.strftime '%Y%m%d%H%M%S'
14
14
  else
15
15
  "%.3d" % (current_migration_number(dirname) + 1)
16
16
  end
17
17
  end
18
-
18
+
19
19
  def copy_files
20
- copy_file "metadata.rb", "app/models/metadata.rb"
21
- migration_template "create_metadata.rb", "db/migrate/create_metadata.rb"
20
+ copy_file 'metadata.rb', 'app/models/metadata.rb'
21
+ migration_template 'create_metadata.rb', 'db/migrate/create_metadata.rb'
22
22
  end
23
23
  end
@@ -1,9 +1,11 @@
1
+ require 'active_record'
2
+
1
3
  module HasMetadata
2
-
4
+
3
5
  # Base class of the {Metadata} model. Functionality is moved to this class to
4
- # make changes to the model easier. See the @Metadata@ method for more
6
+ # make changes to the model easier. See the `Metadata` method for more
5
7
  # information.
6
-
8
+
7
9
  class Model < ActiveRecord::Base
8
10
  self.table_name = 'metadata'
9
11
  serialize :data, Hash
@@ -20,10 +22,10 @@ module HasMetadata
20
22
  name = name.to_sym
21
23
  super(name) or fields.include?(name)
22
24
  end
23
-
25
+
24
26
  # override attribute prefix/suffix methods to get full first-class
25
27
  # property functionality
26
-
28
+
27
29
  singleton_class.send(:define_method, :attribute) do |name|
28
30
  name = name.to_sym
29
31
  super(name) unless fields.include?(name)
@@ -33,7 +35,7 @@ module HasMetadata
33
35
  data.include?(name) ? data[name] : default
34
36
  end
35
37
  singleton_class.send :alias_method, :attribute_before_type_cast, :attribute
36
-
38
+
37
39
  singleton_class.send(:define_method, :query_attribute) do |name|
38
40
  name = name.to_sym
39
41
  super(name) unless fields.include?(name)
@@ -49,19 +51,26 @@ module HasMetadata
49
51
  not send(name).blank?
50
52
  end
51
53
  end
52
-
54
+
53
55
  singleton_class.send(:define_method, :attribute=) do |name, value|
54
56
  name = name.to_sym
55
57
  super(name, value) unless fields.include?(name)
56
58
 
57
59
  options = fields[name] || {}
58
60
  data_will_change!
61
+ attribute_will_change! name.to_s
59
62
  data[name] = HasMetadata.metadata_typecast(value, options[:type])
60
63
  end
61
64
 
62
65
  self
63
66
  end
64
67
 
68
+ # @return [Hash<String, Object>] A hash of metadata fields that have been
69
+ # altered.
70
+ def changed_metadata
71
+ changed_attributes.except(*attribute_names)
72
+ end
73
+
65
74
  private
66
75
 
67
76
  def initialize_data
data/lib/has_metadata.rb CHANGED
@@ -16,15 +16,16 @@ class Object
16
16
  end
17
17
 
18
18
 
19
- # Provides the {ClassMethods#has_metadata} method to subclasses of @ActiveRecord::Base@.
19
+ # Provides the {ClassMethods#has_metadata} method to subclasses of
20
+ # `ActiveRecord::Base`.
20
21
 
21
22
  module HasMetadata
22
23
  extend ActiveSupport::Concern
23
-
24
+
24
25
  # @private
25
26
  def self.metadata_typecast(value, type)
26
27
  if value.kind_of?(String) then
27
- if type == Integer or type == Fixnum then
28
+ if type == Integer or type == Integer then
28
29
  begin
29
30
  return Integer(value.sub(/^0+/, '')) # so that it doesn't think it's in octal
30
31
  rescue ArgumentError
@@ -36,33 +37,37 @@ module HasMetadata
36
37
  rescue ArgumentError
37
38
  return value
38
39
  end
39
- elsif type == Boolean then return value.parse_bool end
40
+ elsif type == Boolean then
41
+ return value.parse_bool
42
+ end
40
43
  end
41
44
  return value
42
45
  end
43
-
46
+
44
47
  # Class methods that are added to your model.
45
-
48
+
46
49
  module ClassMethods
47
50
 
48
51
  # Defines a set of fields whose values exist in the associated {Metadata}
49
- # record. Each key in the @fields@ hash is the name of a metadata field, and
50
- # the value is a set of options to pass to the @validates@ method. If you do
51
- # not want to perform any validation on a field, simply pass @true@ as its
52
+ # record. Each key in the `fields` hash is the name of a metadata field, and
53
+ # the value is a set of options to pass to the `validates` method. If you do
54
+ # not want to perform any validation on a field, simply pass `true` as its
52
55
  # key value.
53
56
  #
54
- # In addition to the normal @validates@ keys, you can also include a @:type@
55
- # key to restrict values to certain classes, or a @:default@ key to specify
57
+ # In addition to the normal `validates` keys, you can also include a `:type`
58
+ # key to restrict values to certain classes, or a `:default` key to specify
56
59
  # a value to return for the getter should none be set (normal default is
57
- # @nil@).
60
+ # `nil`).
58
61
  #
59
62
  # @param [Hash<Symbol, Hash>] fields A mapping of field names to their
60
- # validation options (and/or the @:type@ key).
63
+ # validation options (and/or the `:type` key).
61
64
  #
62
65
  # @example Three metadata fields, one basic, one validated, and one type-checked.
63
- # has_metadata(optional: true, required: { presence: true }, number: { type: Fixnum })
66
+ # has_metadata(optional: true, required: { presence: true }, number: { type: Integer })
64
67
 
65
68
  def has_metadata(fields)
69
+ raise "Can't define Rails-magic timestamped columns as metadata" if (fields.keys & [:created_at, :created_on, :updated_at, :updated_on]).any?
70
+
66
71
  if !respond_to?(:metadata_fields) then
67
72
  belongs_to :metadata, dependent: :destroy
68
73
  accepts_nested_attributes_for :metadata
@@ -73,7 +78,9 @@ module HasMetadata
73
78
 
74
79
  define_method(:save_metadata) { metadata.save! }
75
80
  define_method(:metadata_changed?) { metadata.try :changed? }
76
- else
81
+
82
+ prepend WithMetadata
83
+ elsif metadata_fields.slice(*fields.keys) != fields
77
84
  raise "Cannot redefine existing metadata fields: #{(fields.keys & self.metadata_fields.keys).to_sentence}" unless (fields.keys & self.metadata_fields.keys).empty?
78
85
  self.metadata_fields = self.metadata_fields.merge(fields)
79
86
  end
@@ -81,33 +88,34 @@ module HasMetadata
81
88
  fields.each do |name, options|
82
89
  # delegate all attribute methods to the metadata
83
90
  attribute_method_matchers.each { |matcher| delegate matcher.method_name(name), to: :metadata! }
84
-
91
+
85
92
  if options.kind_of?(Hash) then
86
- type = options.delete(:type)
93
+ type = options.delete(:type)
87
94
  type_validate = !options.delete(:skip_type_validation)
88
95
  options.delete :default
89
-
96
+
90
97
  validate do |obj|
91
98
  value = obj.send(name)
92
- errors.add(name, :incorrect_type) unless
93
- HasMetadata.metadata_typecast(value, type).kind_of?(type) or
99
+ errors.add(name, :incorrect_type) unless HasMetadata.metadata_typecast(value, type).kind_of?(type) or
94
100
  ((options[:allow_nil] and value.nil?) or (options[:allow_blank] and value.blank?))
95
101
  end if type && type_validate
96
- validates(name, options) unless options.empty? or (options.keys - [ :allow_nil, :allow_blank ]).empty?
102
+ validates(name, options) unless options.empty? or (options.keys - [:allow_nil, :allow_blank]).empty?
97
103
  end
98
104
  end
99
105
  end
100
106
  end
101
107
 
108
+ # @private
102
109
  def as_json(options={})
103
- options ||= Hash.new # the JSON encoder can sometimes give us nil options?
104
- options[:except] = Array.wrap(options[:except]) + [ :metadata_id ]
110
+ options ||= Hash.new # the JSON encoder can sometimes give us nil options?
111
+ options[:except] = Array.wrap(options[:except]) + [:metadata_id]
105
112
  options[:methods] = Array.wrap(options[:methods]) + metadata_fields.keys - options[:except].map(&:to_sym)
106
113
  super options
107
114
  end
108
-
115
+
116
+ # @private
109
117
  def to_xml(options={})
110
- options[:except] = Array.wrap(options[:except]) + [ :metadata_id ]
118
+ options[:except] = Array.wrap(options[:except]) + [:metadata_id]
111
119
  options[:methods] = Array.wrap(options[:methods]) + metadata_fields.keys - options[:except].map(&:to_sym)
112
120
  super options
113
121
  end
@@ -115,18 +123,20 @@ module HasMetadata
115
123
  # @private
116
124
  def assign_multiparameter_attributes(pairs)
117
125
  fake_attributes = pairs.select { |(field, _)| self.class.metadata_fields.include? field[0, field.index('(')].to_sym }
126
+ result = super(pairs.except(fake_attributes.keys))
118
127
 
119
128
  fake_attributes.group_by { |(field, _)| field[0, field.index('(')] }.each do |field_name, parts|
120
129
  options = self.class.metadata_fields[field_name.to_sym]
121
130
  if options[:type] then
122
131
  args = parts.each_with_object([]) do |(part_name, value), ary|
123
132
  part_ann = part_name[part_name.index('(') + 1, part_name.length]
124
- index = part_ann.to_i - 1
133
+ index = part_ann.to_i - 1
125
134
  raise "Out-of-bounds multiparameter argument index" unless index >= 0
126
135
  ary[index] = if value.blank? then nil
127
- elsif part_ann.ends_with?('i)') then value.to_i
128
- elsif part_ann.ends_with?('f)') then value.to_f
129
- else value end
136
+ elsif part_ann.ends_with?('i)') then value.to_i
137
+ elsif part_ann.ends_with?('f)') then value.to_f
138
+ else value
139
+ end
130
140
  end
131
141
  args.compact!
132
142
  send :"#{field_name}=", options[:type].new(*args) unless args.empty?
@@ -135,22 +145,47 @@ module HasMetadata
135
145
  end
136
146
  end
137
147
 
138
- super(pairs - fake_attributes)
148
+ return result
139
149
  end
140
150
 
141
151
  # @return [Metadata] An existing associated {Metadata} instance, or new,
142
152
  # saved one if none was found.
143
153
 
144
154
  def metadata!
145
- if instance_variables.include?(:@metadata) then
146
- metadata.set_fields self.class.metadata_fields
155
+ if instance_variables.include?(:@metadata) && metadata then
156
+ metadata
147
157
  else
148
- (metadata || Metadata.transaction { metadata || create_metadata }).set_fields self.class.metadata_fields
149
- end
158
+ if new_record? then
159
+ metadata || build_metadata
160
+ else
161
+ metadata || Metadata.transaction { metadata || create_metadata }
162
+ end
163
+ end.set_fields self.class.metadata_fields
150
164
  end
151
165
 
152
166
  # @private
153
167
  def inspect
154
- "#<#{self.class.to_s} #{attributes.merge(metadata.try(:data).try(:stringify_keys) || {}).map { |k,v| "#{k}: #{v.inspect}" }.join(', ')}>"
168
+ "#<#{self.class.to_s} #{attributes.merge(metadata.try(:data).try(:stringify_keys) || {}).map { |k, v| "#{k}: #{v.inspect}" }.join(', ')}>"
169
+ end
170
+
171
+ module WithMetadata
172
+ # @private
173
+ def changed_attributes
174
+ super.merge(metadata.try(:changed_metadata) || {})
175
+ end
176
+
177
+ # @private
178
+ def attributes_changed_by_setter
179
+ super.merge(metadata.try(:changed_metadata) || {})
180
+ end
181
+
182
+ # @private
183
+ def attribute_will_change!(attr)
184
+ if attribute_names.include?(attr) then
185
+ super attr
186
+ else
187
+ metadata!.send :attribute_will_change!, attr
188
+ end
189
+ end
155
190
  end
156
191
  end
@@ -1,11 +1,14 @@
1
1
  # Stores information about a model that doesn't need to be in that model's
2
- # table. Each row in the @metadata@ table stores a schemaless, serialized hash
2
+ # table. Each row in the `metadata` table stores a schemaless, serialized hash
3
3
  # of data associated with a model instance. Any model can have an associated row
4
- # in the @metadata@ table by using the {HasMetadata} module.
4
+ # in the `metadata` table by using the {HasMetadata} module.
5
5
  #
6
- # h2. Properties
6
+ # Properties
7
+ # ----------
7
8
  #
8
- # | @data@ | A hash of this metadata's contents (YAML serialized in the database). |
9
+ # | | |
10
+ # |:-------|:----------------------------------------------------------------------|
11
+ # | `data` | A hash of this metadata's contents (YAML serialized in the database). |
9
12
 
10
13
  class Metadata < HasMetadata::Model
11
14
  end
metadata CHANGED
@@ -1,93 +1,112 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: has_metadata
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
5
- prerelease:
4
+ version: 1.6.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Tim Morgan
9
- autorequire:
10
8
  bindir: bin
11
9
  cert_chain: []
12
- date: 2012-01-24 00:00:00.000000000 Z
10
+ date: 2013-12-08 00:00:00.000000000 Z
13
11
  dependencies:
14
12
  - !ruby/object:Gem::Dependency
15
13
  name: rails
16
- requirement: &70170864527740 !ruby/object:Gem::Requirement
17
- none: false
14
+ requirement: !ruby/object:Gem::Requirement
18
15
  requirements:
19
- - - ! '>='
16
+ - - ">="
20
17
  - !ruby/object:Gem::Version
21
18
  version: '3.2'
22
19
  type: :runtime
23
20
  prerelease: false
24
- version_requirements: *70170864527740
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '3.2'
25
26
  - !ruby/object:Gem::Dependency
26
27
  name: boolean
27
- requirement: &70170864527260 !ruby/object:Gem::Requirement
28
- none: false
28
+ requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - ! '>='
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70170864527260
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
36
40
  - !ruby/object:Gem::Dependency
37
41
  name: jeweler
38
- requirement: &70170864526780 !ruby/object:Gem::Requirement
39
- none: false
42
+ requirement: !ruby/object:Gem::Requirement
40
43
  requirements:
41
- - - ! '>='
44
+ - - ">="
42
45
  - !ruby/object:Gem::Version
43
46
  version: '0'
44
47
  type: :development
45
48
  prerelease: false
46
- version_requirements: *70170864526780
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
47
54
  - !ruby/object:Gem::Dependency
48
55
  name: yard
49
- requirement: &70170864526300 !ruby/object:Gem::Requirement
50
- none: false
56
+ requirement: !ruby/object:Gem::Requirement
51
57
  requirements:
52
- - - ! '>='
58
+ - - ">="
53
59
  - !ruby/object:Gem::Version
54
60
  version: '0'
55
61
  type: :development
56
62
  prerelease: false
57
- version_requirements: *70170864526300
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
58
68
  - !ruby/object:Gem::Dependency
59
69
  name: RedCloth
60
- requirement: &70170864525820 !ruby/object:Gem::Requirement
61
- none: false
70
+ requirement: !ruby/object:Gem::Requirement
62
71
  requirements:
63
- - - ! '>='
72
+ - - ">="
64
73
  - !ruby/object:Gem::Version
65
74
  version: '0'
66
75
  type: :development
67
76
  prerelease: false
68
- version_requirements: *70170864525820
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
69
82
  - !ruby/object:Gem::Dependency
70
83
  name: sqlite3
71
- requirement: &70170864525340 !ruby/object:Gem::Requirement
72
- none: false
84
+ requirement: !ruby/object:Gem::Requirement
73
85
  requirements:
74
- - - ! '>='
86
+ - - ">="
75
87
  - !ruby/object:Gem::Version
76
88
  version: '0'
77
89
  type: :development
78
90
  prerelease: false
79
- version_requirements: *70170864525340
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
80
96
  - !ruby/object:Gem::Dependency
81
97
  name: rspec
82
- requirement: &70170864524860 !ruby/object:Gem::Requirement
83
- none: false
98
+ requirement: !ruby/object:Gem::Requirement
84
99
  requirements:
85
- - - ! '>='
100
+ - - ">="
86
101
  - !ruby/object:Gem::Version
87
102
  version: '0'
88
103
  type: :development
89
104
  prerelease: false
90
- version_requirements: *70170864524860
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
91
110
  description: has_metadata lets you move non-indexed and weighty columns off of your
92
111
  big tables by creating a separate metadata table to store all this extra information.
93
112
  Works with Ruby 1.9. and Rails 3.0.
@@ -96,10 +115,10 @@ executables: []
96
115
  extensions: []
97
116
  extra_rdoc_files:
98
117
  - LICENSE
99
- - README.textile
118
+ - README.md
100
119
  files:
101
120
  - LICENSE
102
- - README.textile
121
+ - README.md
103
122
  - has_metadata.gemspec
104
123
  - lib/has_metadata.rb
105
124
  - lib/has_metadata/metadata_generator.rb
@@ -108,27 +127,32 @@ files:
108
127
  - templates/metadata.rb
109
128
  homepage: http://github.com/riscfuture/has_metadata
110
129
  licenses: []
111
- post_install_message:
130
+ metadata: {}
131
+ post_install_message: |2+
132
+
133
+ ⚠️ DEPRECATED: has_metadata is no longer maintained.
134
+
135
+ Superseded by `has_metadata_column` (also deprecated as of this notice). No active maintenance.
136
+
137
+ This is the final release. No further updates are planned.
138
+
112
139
  rdoc_options: []
113
140
  require_paths:
114
141
  - lib
115
142
  required_ruby_version: !ruby/object:Gem::Requirement
116
- none: false
117
143
  requirements:
118
- - - ! '>='
144
+ - - ">="
119
145
  - !ruby/object:Gem::Version
120
146
  version: '1.9'
121
147
  required_rubygems_version: !ruby/object:Gem::Requirement
122
- none: false
123
148
  requirements:
124
- - - ! '>='
149
+ - - ">="
125
150
  - !ruby/object:Gem::Version
126
151
  version: '0'
127
152
  requirements: []
128
- rubyforge_project:
129
- rubygems_version: 1.8.15
130
- signing_key:
131
- specification_version: 3
132
- summary: Reduce your table width by moving non-indexed columns to a separate metadata
133
- table
153
+ rubygems_version: 4.0.11
154
+ specification_version: 4
155
+ summary: "[DEPRECATED] Reduce your table width by moving non-indexed columns to a
156
+ separate metadata table"
134
157
  test_files: []
158
+ ...
data/README.textile DELETED
@@ -1,126 +0,0 @@
1
- h1. has_metadata -- Keep your tables narrow
2
-
3
- | *Author* | Tim Morgan |
4
- | *Version* | 1.6 (Jan 23, 2012) |
5
- | *License* | Released under the MIT License. |
6
-
7
- h2. Important note for those upgrading from 1.0 to 1.1
8
-
9
- You must re-run the @rails generate metadata@ task to update your @Metadata@
10
- model. When finished, your @app/models/metadata.rb@ file should look like:
11
-
12
- <pre><code>
13
- # Stores information about a model that doesn't need to be in that model's
14
- # table. Each row in the @metadata@ table stores a schemaless, serialized hash
15
- # of data associated with a model instance. Any model can have an associated row
16
- # in the @metadata@ table by using the {HasMetadata} module.
17
- #
18
- # h2. Properties
19
- #
20
- # | @data@ | A hash of this metadata's contents (YAML serialized in the database). |
21
-
22
- class Metadata &lt; HasMetadata::Model
23
- end
24
- </code></pre>
25
-
26
- Note that this is significantly emptier than the previous model.
27
-
28
- h2. About
29
-
30
- Wide tables are a problem for big databases. If your @ActiveRecord@ models have
31
- 10, maybe 15 columns, some of which are @VARCHARs@ or maybe even @TEXTs@, it's
32
- going to slow your queries down when you start to scale up.
33
-
34
- The easy solution to this problem is to limit your projections; in other words,
35
- to only @SELECT@ the columns that you actually need. If you've got a @users@
36
- table with a giant @about_me@ text column, and you're only trying to look up the
37
- user's login, then just select the @login@ column.
38
-
39
- In the long run, though, a superior solution is to just move those
40
- @about_me@-type columns to a completely different table. This table has just one
41
- JSON-serialized field, making it schemaless, so it doesn't waste space. Each row
42
- in this table is associated with a record in another table (@Metadata@ @has_one@
43
- of your models).
44
-
45
- This way, when your website gets huge, all of your giant, freeform data is in
46
- one table that you can shard, or move off to an alternate database, or even a
47
- NoSQL-type document store, or otherwise manage as you please. Your relational
48
- tables remain slim and efficient, containing only columns that a) are indexed,
49
- or b) you need frequent access to.
50
-
51
- This gem includes a generator that creates the @Metadata@ model, and a module
52
- that you can include in your models to define which fields have been spun off to
53
- the metadata record.
54
-
55
- h2. Installation
56
-
57
- *Important Note:* This gem is only compatible with Ruby 1.9 and Rails 3.0.
58
-
59
- Firstly, add the gem to your Rails project's @Gemfile@:
60
-
61
- <pre><code>
62
- gem 'has_metadata'
63
- </code></pre>
64
-
65
- Next, run the generator, which will add the @Metadata@ model and its migration
66
- to your application.
67
-
68
- <pre><code>
69
- rails generate metadata
70
- </code></pre>
71
-
72
- h2. Usage
73
-
74
- The first thing to think about is what columns to keep in your model. You will
75
- need to keep any indexed columns, or any columns you perform lookups or other
76
- SQL queries with. You should also keep any frequently accessed columns,
77
- especially if they are small (integers or booleans). Good candidates for the
78
- metadata table are the @TEXT@- and @VARCHAR@-type columns that you only need to
79
- render a page or two in your app.
80
-
81
- You'll need to change your model's schema so that it has a @metadata_id@ column
82
- that will associate the model with its @Metadata@ instance:
83
-
84
- <pre><code>
85
- t.belongs_to :metadata
86
- </code></pre>
87
-
88
- Next, include the @HasMetadata@ module in your model, and call the
89
- @has_metadata@ method to define the schema of your metadata. You can get more
90
- information in the {HasMetadata::ClassMethods#has_metadata} documentation, but for starters, here's a
91
- basic example:
92
-
93
- <pre><code>
94
- class User < ActiveRecord::Base
95
- include HasMetadata
96
- has_metadata({
97
- about_me: { type: String, length: { maximum: 512 } },
98
- birthdate: { type: Date, presence: true },
99
- zipcode: { type: Number, numericality: { greater_than: 9999, less_than: 10_000_} }
100
- })
101
- end
102
- </code></pre>
103
-
104
- As you can see, you pass field names mapped to a hash. The hash describes the
105
- validation that will be performed, and is in the same format as a call to
106
- @validates@. In addition to the @EachValidator@ keys shown above, you can also
107
- pass a @type@ key, to constrain the Ruby type that can be assigned to the field.
108
-
109
- Each of these fields (in this case, @about_me@, @birthdate@, and @zipcode@) can
110
- be accessed and set as first_level methods on an instance of your model:
111
-
112
- <pre><code>
113
- user.about_me #=> "I was born in 1982 in Aberdeen. My father was a carpenter from..."
114
- </code></pre>
115
-
116
- ... and thus, used as part of @form_for@ fields:
117
-
118
- <pre><code>
119
- form_for user do |f|
120
- f.text_area :about_me, rows: 5, cols: 80
121
- end
122
- </code></pre>
123
-
124
- The only thing you _can't_ do is use these fields in a query, obviously. You
125
- can't do something like @User.where(zipcode: 90210)@, because that column
126
- doesn't exist on the @users@ table.