acts_as_customized_attributes 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/README.md +3 -3
- data/Rakefile +15 -11
- data/config/routes.rb +1 -0
- data/lib/acts_as_customized_attributes.rb +1 -0
- data/lib/acts_as_customized_attributes/class_methods.rb +95 -13
- data/lib/acts_as_customized_attributes/compatibility.rb +1 -0
- data/lib/acts_as_customized_attributes/engine.rb +4 -2
- data/lib/acts_as_customized_attributes/instance_methods.rb +7 -6
- data/lib/acts_as_customized_attributes/version.rb +2 -1
- data/lib/tasks/acts_as_customized_attributes_tasks.rake +1 -0
- data/spec/dummy/Rakefile +2 -1
- data/spec/dummy/app/controllers/application_controller.rb +1 -0
- data/spec/dummy/app/helpers/application_helper.rb +1 -0
- data/spec/dummy/app/models/order.rb +1 -0
- data/spec/dummy/app/models/user.rb +1 -0
- data/spec/dummy/config.ru +2 -1
- data/spec/dummy/config/application.rb +4 -4
- data/spec/dummy/config/boot.rb +6 -5
- data/spec/dummy/config/database.example.yml +6 -37
- data/spec/dummy/config/database.shippable.yml +2 -5
- data/spec/dummy/config/database.yml +9 -16
- data/spec/dummy/config/environment.rb +2 -1
- data/spec/dummy/config/environments/development.rb +2 -0
- data/spec/dummy/config/environments/production.rb +3 -1
- data/spec/dummy/config/environments/test.rb +4 -2
- data/spec/dummy/config/initializers/backtrace_silencers.rb +1 -0
- data/spec/dummy/config/initializers/inflections.rb +1 -0
- data/spec/dummy/config/initializers/mime_types.rb +1 -0
- data/spec/dummy/config/initializers/secret_token.rb +3 -1
- data/spec/dummy/config/initializers/session_store.rb +2 -1
- data/spec/dummy/config/initializers/wrap_parameters.rb +1 -0
- data/spec/dummy/config/routes.rb +1 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20141118114902_create_users.rb +1 -0
- data/spec/dummy/db/migrate/20141118114941_create_user_customized_attributes.rb +1 -0
- data/spec/dummy/db/migrate/20141118134833_create_orders.rb +1 -0
- data/spec/dummy/db/migrate/20141118135027_create_order_customized_attributes.rb +1 -0
- data/spec/dummy/db/schema.rb +16 -16
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +153 -0
- data/spec/dummy/log/test.log +2278 -0
- data/spec/dummy/script/rails +4 -3
- data/spec/factories/order.rb +1 -0
- data/spec/factories/user.rb +1 -0
- data/spec/models/user_spec.rb +23 -22
- data/spec/spec_helper.rb +8 -7
- metadata +64 -34
- data/app/models/acts_as_customized_attributes/data.rb +0 -29
- data/app/models/acts_as_customized_attributes/data_key.rb +0 -52
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
MjM5NGRkYzIzZTBlYTUzYWU2MDljNGI0ZTAwZWE5ODAxMjM4M2Y2Zg==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6cf3da61d6819da1a7d8562dcad8619affda62f5
|
4
|
+
data.tar.gz: 36bc64c145508ac95af5dfe0045854979bc13412
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
MjRjMWVhMWI5MDllNTEwYWVhMzNkZDhkODYzNjFkODc2MGRmZGRmN2FmNzA3
|
11
|
-
MTI2NzgwYzc4NDgxOGI4ZTU3NjEzYWExN2ZmZDNiNTA3ODU0NzI=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ODM1NWFkM2FjZDY1ODUxMGZiZDhiZjYyMWExYTAzODUxYWY1ZGIyZThlZTQx
|
14
|
-
YzdhYWRmYTI4ZmVlMjE5NTFkNGQ3ZmU1ZGMxOGIzNjgxMDgyYzc2NTcxODA0
|
15
|
-
YzcwMGUxYmZmZDUzZmYzZmEwZTFlNjFiNzE0NGNhODkyYzg4Yjk=
|
6
|
+
metadata.gz: b0947725f00d7d5f619a78f7a291f0a7250752a8730f2f29ffb6d6dc5da16e8eb65109a31b87a81962ca44ceeb140a8ed13d50f4123c2b8c619f90af3e78b037
|
7
|
+
data.tar.gz: 82dfbf339ae77a97b164b94ed38c61ee5e4fa2fd0689af80108a5c743cab765f24c72186b0948f36f26e93f092352438d3ed06f4867e623a75c2823c57494440
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
[![Build Status](https://api.shippable.com/projects/546b3f7bd46935d5fbbde6b9/badge?branchName=master)](https://app.shippable.com/projects/546b3f7bd46935d5fbbde6b9/builds/latest)
|
2
1
|
[![Code Climate](https://codeclimate.com/github/kaspernj/acts_as_customized_attributes/badges/gpa.svg)](https://codeclimate.com/github/kaspernj/acts_as_customized_attributes)
|
3
2
|
[![Test Coverage](https://codeclimate.com/github/kaspernj/acts_as_customized_attributes/badges/coverage.svg)](https://codeclimate.com/github/kaspernj/acts_as_customized_attributes)
|
3
|
+
[![Build Status](https://img.shields.io/shippable/546b3f7bd46935d5fbbde6b9.svg)](https://app.shippable.com/projects/546b3f7bd46935d5fbbde6b9/builds/latest)
|
4
4
|
|
5
5
|
# ActsAsCustomizedAttributes
|
6
6
|
|
@@ -59,13 +59,13 @@ some_model.customized_attributes #=> {:my_custom_attribute => 5}
|
|
59
59
|
#### Query keys.
|
60
60
|
|
61
61
|
```ruby
|
62
|
-
|
62
|
+
SomeModelDataKey.where("name LIKE '%facebook%'")
|
63
63
|
```
|
64
64
|
|
65
65
|
### Query data
|
66
66
|
|
67
67
|
```ruby
|
68
|
-
|
68
|
+
SomeModelData.where("resource_id > 5")
|
69
69
|
```
|
70
70
|
|
71
71
|
### Optimize inserts with transactions for inserts / updates.
|
data/Rakefile
CHANGED
@@ -1,26 +1,30 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
+
# frozen_string_literal: true
|
2
3
|
begin
|
3
|
-
require
|
4
|
+
require "bundler/setup"
|
4
5
|
rescue LoadError
|
5
|
-
puts
|
6
|
+
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
6
7
|
end
|
7
8
|
begin
|
8
|
-
require
|
9
|
+
require "rdoc/task"
|
9
10
|
rescue LoadError
|
10
|
-
require
|
11
|
-
require
|
11
|
+
require "rdoc/rdoc"
|
12
|
+
require "rake/rdoctask"
|
12
13
|
RDoc::Task = Rake::RDocTask
|
13
14
|
end
|
14
15
|
|
15
16
|
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
-
rdoc.rdoc_dir =
|
17
|
-
rdoc.title =
|
18
|
-
rdoc.options <<
|
19
|
-
rdoc.rdoc_files.include(
|
20
|
-
rdoc.rdoc_files.include(
|
17
|
+
rdoc.rdoc_dir = "rdoc"
|
18
|
+
rdoc.title = "ActsAsCustomizedAttributes"
|
19
|
+
rdoc.options << "--line-numbers"
|
20
|
+
rdoc.rdoc_files.include("README.md")
|
21
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
21
22
|
end
|
22
23
|
|
23
24
|
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
24
|
-
load
|
25
|
+
load "rails/tasks/engine.rake"
|
26
|
+
|
27
|
+
require "best_practice_project"
|
28
|
+
BestPracticeProject.load_tasks
|
25
29
|
|
26
30
|
Bundler::GemHelper.install_tasks
|
data/config/routes.rb
CHANGED
@@ -1,20 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ActsAsCustomizedAttributes::ClassMethods
|
2
|
-
def acts_as_customized_attributes(
|
3
|
+
def acts_as_customized_attributes(_args = {})
|
3
4
|
$aaca_class_name_key = "#{name}DataKey"
|
4
5
|
$aaca_class_name_data = "#{name}Data"
|
5
6
|
$original_class_name = name
|
6
7
|
|
7
|
-
class_data_key = Class.new(
|
8
|
-
set_table_name
|
8
|
+
class_data_key = Class.new(ActiveRecord::Base) do
|
9
|
+
if respond_to?(:set_table_name)
|
10
|
+
set_table_name $aaca_class_name_key.tableize
|
11
|
+
else
|
12
|
+
self.table_name = $aaca_class_name_key.tableize
|
13
|
+
end
|
14
|
+
|
15
|
+
after_create :add_to_cache
|
16
|
+
after_update :add_to_cache
|
17
|
+
after_destroy :remove_from_cache
|
18
|
+
before_update :remove_from_cache
|
19
|
+
|
20
|
+
validates_presence_of :name
|
21
|
+
validate :validate_unique_name
|
9
22
|
|
10
|
-
has_many :data, class_name: $aaca_class_name_data, foreign_key: "data_key_id", dependent: :destroy
|
23
|
+
has_many :data, class_name: $aaca_class_name_data.to_s, table_name: $aaca_class_name_data.tableize.to_s, foreign_key: "data_key_id", dependent: :destroy
|
24
|
+
|
25
|
+
def self.id_for_name(name)
|
26
|
+
cache_name_to_id.fetch(name.to_s)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.name_for_id(id)
|
30
|
+
cache_name_to_id.key(id) || raise(KeyError, "No such ID: #{id}")
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.cache_name_to_id
|
34
|
+
update_cache_name_to_id unless @cache_name_to_id
|
35
|
+
@cache_name_to_id
|
36
|
+
end
|
37
|
+
|
38
|
+
# Initializes / reloads the cache.
|
39
|
+
def self.update_cache_name_to_id
|
40
|
+
@cache_name_to_id = {}
|
41
|
+
find_each do |data_key|
|
42
|
+
@cache_name_to_id[data_key.name] = data_key.id
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def add_to_cache
|
49
|
+
self.class.cache_name_to_id[name.to_s] = id
|
50
|
+
end
|
51
|
+
|
52
|
+
def remove_from_cache
|
53
|
+
self.class.cache_name_to_id.delete(name_was)
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate_unique_name
|
57
|
+
id_exists = self.class.id_for_name(name)
|
58
|
+
|
59
|
+
errors.add :name, :taken if id_exists != id
|
60
|
+
rescue KeyError
|
61
|
+
# No problem.
|
62
|
+
end
|
11
63
|
end
|
12
64
|
|
13
|
-
class_data = Class.new(
|
14
|
-
set_table_name
|
65
|
+
class_data = Class.new(ActiveRecord::Base) do
|
66
|
+
if respond_to?(:set_table_name)
|
67
|
+
set_table_name $aaca_class_name_data.tableize
|
68
|
+
else
|
69
|
+
self.table_name = $aaca_class_name_data.tableize
|
70
|
+
end
|
71
|
+
|
72
|
+
belongs_to :resource, class_name: $original_class_name.to_s
|
73
|
+
belongs_to :data_key, class_name: $aaca_class_name_key.to_s
|
74
|
+
|
75
|
+
validate :associated_resource_and_data_key
|
76
|
+
|
77
|
+
def self.key_class=(key_class)
|
78
|
+
@key_class = key_class
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.key_class
|
82
|
+
@key_class
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def associated_resource_and_data_key
|
88
|
+
return errors.add :data_key_id, "not valid" unless data_key_id?
|
15
89
|
|
16
|
-
|
17
|
-
|
90
|
+
if !resource_id? || !resource
|
91
|
+
return errors.add :resource_id, "not associated"
|
92
|
+
end
|
93
|
+
|
94
|
+
begin
|
95
|
+
self.class.key_class.name_for_id(data_key_id)
|
96
|
+
rescue KeyError
|
97
|
+
errors.add :data_key_id, "doesn't exist"
|
98
|
+
end
|
99
|
+
end
|
18
100
|
end
|
19
101
|
|
20
102
|
Object.const_set($aaca_class_name_key, class_data_key)
|
@@ -59,8 +141,9 @@ private
|
|
59
141
|
def migration_class
|
60
142
|
$acts_as_customized_attributes_keys_table_name = "#{name.downcase}_data_keys"
|
61
143
|
$acts_as_customized_attributes_table_name = "#{name.downcase}_data"
|
144
|
+
$table_name = table_name
|
62
145
|
|
63
|
-
|
146
|
+
Class.new(ActiveRecord::Migration) do
|
64
147
|
def up
|
65
148
|
create_table $acts_as_customized_attributes_keys_table_name do |t|
|
66
149
|
t.string :name
|
@@ -71,14 +154,13 @@ private
|
|
71
154
|
add_index $acts_as_customized_attributes_keys_table_name, :name, unique: true
|
72
155
|
|
73
156
|
create_table $acts_as_customized_attributes_table_name do |t|
|
74
|
-
t.belongs_to :resource
|
75
|
-
t.belongs_to :data_key
|
157
|
+
t.belongs_to :resource, index: true
|
158
|
+
t.belongs_to :data_key, index: true
|
76
159
|
t.string :value
|
77
160
|
t.timestamps
|
78
161
|
end
|
79
162
|
|
80
|
-
|
81
|
-
add_index $acts_as_customized_attributes_table_name, :resource_id
|
163
|
+
add_foreign_key $acts_as_customized_attributes_table_name, $table_name, column: "data_key_id", on_delete: :cascade
|
82
164
|
add_index $acts_as_customized_attributes_table_name, [:data_key_id, :resource_id], unique: true
|
83
165
|
end
|
84
166
|
|
@@ -1,13 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ActsAsCustomizedAttributes::InstanceMethods
|
2
3
|
def update_customized_attributes(data)
|
3
4
|
update_customized_attributes_with_args(data: data)
|
4
5
|
end
|
5
6
|
|
6
|
-
UPDATE_CUSTOMIZED_ATTRIBUTES_VALID_ARGS = [:data, :transactioner]
|
7
|
+
UPDATE_CUSTOMIZED_ATTRIBUTES_VALID_ARGS = [:data, :transactioner].freeze
|
7
8
|
def update_customized_attributes_with_args(args)
|
8
|
-
args.each { |key,
|
9
|
+
args.each { |key, _value| raise "Invalid argument: '#{key}'." unless UPDATE_CUSTOMIZED_ATTRIBUTES_VALID_ARGS.include?(key) }
|
9
10
|
|
10
|
-
args
|
11
|
+
args.fetch(:data).each do |key, value|
|
11
12
|
begin
|
12
13
|
key_id = self.class.aaca_key_class.id_for_name(key)
|
13
14
|
rescue KeyError
|
@@ -15,12 +16,12 @@ module ActsAsCustomizedAttributes::InstanceMethods
|
|
15
16
|
key_id = key_model.id
|
16
17
|
end
|
17
18
|
|
18
|
-
data_model =
|
19
|
+
data_model = data.where(data_key_id: key_id).first
|
19
20
|
if data_model
|
20
21
|
data_model.resource = self # Saves query when validating.
|
21
22
|
else
|
22
23
|
# Set resource in order to skip query when validating.
|
23
|
-
data_model =
|
24
|
+
data_model = data.new(data_key_id: key_id, resource: self)
|
24
25
|
end
|
25
26
|
|
26
27
|
data_model.value = value
|
@@ -45,6 +46,6 @@ module ActsAsCustomizedAttributes::InstanceMethods
|
|
45
46
|
hash[key_name.to_sym] = data_i.value
|
46
47
|
end
|
47
48
|
|
48
|
-
|
49
|
+
hash
|
49
50
|
end
|
50
51
|
end
|
data/spec/dummy/Rakefile
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
3
4
|
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
4
5
|
|
5
|
-
require File.expand_path(
|
6
|
+
require File.expand_path("../config/application", __FILE__)
|
6
7
|
|
7
8
|
Dummy::Application.load_tasks
|
data/spec/dummy/config.ru
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require File.expand_path("../boot", __FILE__)
|
2
3
|
|
3
|
-
require
|
4
|
+
require "rails/all"
|
4
5
|
|
5
6
|
Bundler.require
|
6
7
|
require "acts_as_customized_attributes"
|
@@ -39,7 +40,6 @@ module Dummy
|
|
39
40
|
config.assets.enabled = true
|
40
41
|
|
41
42
|
# Version of your assets, change this if you want to expire all your assets
|
42
|
-
config.assets.version =
|
43
|
+
config.assets.version = "1.0"
|
43
44
|
end
|
44
45
|
end
|
45
|
-
|
data/spec/dummy/config/boot.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "rubygems"
|
3
|
+
gemfile = File.expand_path("../../../../Gemfile", __FILE__)
|
3
4
|
|
4
5
|
if File.exist?(gemfile)
|
5
|
-
ENV[
|
6
|
-
require
|
6
|
+
ENV["BUNDLE_GEMFILE"] = gemfile
|
7
|
+
require "bundler"
|
7
8
|
Bundler.setup
|
8
9
|
end
|
9
10
|
|
10
|
-
|
11
|
+
$LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__)
|
@@ -1,42 +1,11 @@
|
|
1
|
-
# MySQL. Versions 4.1 and 5.0 are recommended.
|
2
|
-
#
|
3
|
-
# Install the MYSQL driver
|
4
|
-
# gem install mysql2
|
5
|
-
#
|
6
|
-
# Ensure the MySQL gem is defined in your Gemfile
|
7
|
-
# gem 'mysql2'
|
8
|
-
#
|
9
|
-
# And be sure to use new-style password hashing:
|
10
|
-
# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
|
11
1
|
development:
|
12
|
-
adapter:
|
13
|
-
|
14
|
-
reconnect: false
|
15
|
-
database: dummy_development
|
16
|
-
pool: 5
|
17
|
-
username: root
|
18
|
-
password:
|
19
|
-
socket: /var/run/mysqld/mysqld.sock
|
2
|
+
adapter: sqlite3
|
3
|
+
database: db/development.sqlite3
|
20
4
|
|
21
|
-
# Warning: The database defined as "test" will be erased and
|
22
|
-
# re-generated from your development database when you run "rake".
|
23
|
-
# Do not set this db to the same as development or production.
|
24
5
|
test:
|
25
|
-
adapter:
|
26
|
-
|
27
|
-
reconnect: false
|
28
|
-
database: dummy_test
|
29
|
-
pool: 5
|
30
|
-
username: root
|
31
|
-
password:
|
32
|
-
socket: /var/run/mysqld/mysqld.sock
|
6
|
+
adapter: sqlite3
|
7
|
+
database: db/test.sqlite3
|
33
8
|
|
34
9
|
production:
|
35
|
-
adapter:
|
36
|
-
|
37
|
-
reconnect: false
|
38
|
-
database: dummy_production
|
39
|
-
pool: 5
|
40
|
-
username: root
|
41
|
-
password:
|
42
|
-
socket: /var/run/mysqld/mysqld.sock
|
10
|
+
adapter: sqlite3
|
11
|
+
database: db/production.sqlite3
|