hydra_attribute 0.3.2 → 0.4.0.rc1
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.
- data/CHANGELOG.md +1 -1
- data/README.md +7 -0
- data/features/entity/create.feature +128 -0
- data/features/entity/destroy.feature +111 -0
- data/features/entity/new.feature +121 -0
- data/features/entity/update.feature +147 -0
- data/features/{attributes → hydra_attribute}/create.feature +7 -7
- data/features/{attributes → hydra_attribute}/destroy.feature +2 -4
- data/features/{attributes → hydra_attribute}/update.feature +10 -10
- data/features/hydra_set/destroy.feature +31 -0
- data/features/migrations/create_and_drop.feature +165 -0
- data/features/migrations/migrate_and_rollback.feature +211 -0
- data/features/relation/query_methods/group.feature +42 -0
- data/features/relation/query_methods/order.feature +67 -0
- data/features/relation/query_methods/reorder.feature +29 -0
- data/features/relation/query_methods/reverse_order.feature +29 -0
- data/features/relation/query_methods/select.feature +50 -0
- data/features/relation/query_methods/where.feature +70 -0
- data/features/step_definitions/connections.rb +65 -0
- data/features/step_definitions/model_steps.rb +79 -6
- data/features/step_definitions/query_methods.rb +3 -3
- data/features/step_definitions/record_steps.rb +3 -4
- data/features/support/env.rb +17 -3
- data/features/support/world.rb +15 -10
- data/gemfiles/3.1.gemfile.lock +15 -15
- data/gemfiles/3.2.gemfile.lock +15 -15
- data/lib/hydra_attribute/active_record/association.rb +74 -38
- data/lib/hydra_attribute/active_record/association_preloader.rb +49 -49
- data/lib/hydra_attribute/active_record/attribute_methods.rb +37 -85
- data/lib/hydra_attribute/active_record/migration.rb +2 -2
- data/lib/hydra_attribute/active_record/reflection.rb +1 -1
- data/lib/hydra_attribute/active_record/relation/query_methods.rb +8 -7
- data/lib/hydra_attribute/active_record/relation.rb +1 -0
- data/lib/hydra_attribute/active_record.rb +20 -12
- data/lib/hydra_attribute/association_builder.rb +1 -2
- data/lib/hydra_attribute/builder.rb +7 -8
- data/lib/hydra_attribute/entity_callbacks.rb +12 -32
- data/lib/hydra_attribute/hydra_attribute.rb +25 -16
- data/lib/hydra_attribute/hydra_attribute_methods.rb +85 -0
- data/lib/hydra_attribute/hydra_methods.rb +123 -0
- data/lib/hydra_attribute/hydra_set.rb +36 -0
- data/lib/hydra_attribute/hydra_set_methods.rb +39 -0
- data/lib/hydra_attribute/hydra_value_methods.rb +14 -0
- data/lib/hydra_attribute/memoize.rb +37 -0
- data/lib/hydra_attribute/migrator.rb +100 -51
- data/lib/hydra_attribute/railtie.rb +1 -3
- data/lib/hydra_attribute/version.rb +1 -1
- data/lib/hydra_attribute.rb +7 -1
- data/spec/hydra_attribute_methods_spec.rb +458 -0
- data/spec/hydra_attribute_spec.rb +19 -0
- data/spec/hydra_methods_spec.rb +457 -0
- data/spec/hydra_set_methods_spec.rb +203 -0
- data/spec/hydra_set_spec.rb +19 -0
- data/spec/memoize_spec.rb +95 -0
- data/spec/spec_helper.rb +42 -2
- metadata +71 -43
- data/features/create.feature +0 -47
- data/features/define.feature +0 -38
- data/features/destroy.feature +0 -102
- data/features/query_methods/group.feature +0 -42
- data/features/query_methods/order.feature +0 -99
- data/features/query_methods/select.feature +0 -50
- data/features/query_methods/where.feature +0 -70
- data/features/support/schema.rb +0 -79
- data/features/update.feature +0 -114
@@ -0,0 +1,70 @@
|
|
1
|
+
Feature: hydra attribute where conditions
|
2
|
+
When filter by hydra attribute and this value is not nil
|
3
|
+
Then records with this attribute should be selected
|
4
|
+
|
5
|
+
When filter by hydra attribute and this value is nil
|
6
|
+
Then records with nil and blank value should be selected
|
7
|
+
|
8
|
+
Background: create hydra attributes
|
9
|
+
Given create hydra attributes for "Product" with role "admin" as "hashes":
|
10
|
+
| name | backend_type | white_list |
|
11
|
+
| code | string | [bool:t] |
|
12
|
+
| summary | string | [bool:t] |
|
13
|
+
| title | string | [bool:t] |
|
14
|
+
| price | float | [bool:t] |
|
15
|
+
| active | boolean | [bool:t] |
|
16
|
+
| state | integer | [bool:t] |
|
17
|
+
|
18
|
+
Scenario: filter by one hydra attribute
|
19
|
+
Given create "Product" model with attributes as "hashes":
|
20
|
+
| code | price |
|
21
|
+
| 1 | 2.75 |
|
22
|
+
| 2 | 2.75 |
|
23
|
+
| 3 | 2.76 |
|
24
|
+
| 4 | |
|
25
|
+
When filter "Product" by:
|
26
|
+
| field | value |
|
27
|
+
| price | 2.75 |
|
28
|
+
Then total records should be "2"
|
29
|
+
And records should have the following attributes:
|
30
|
+
| field | value |
|
31
|
+
| code | 1 |
|
32
|
+
| code | 2 |
|
33
|
+
|
34
|
+
Scenario: filter by one hydra attribute with nil value
|
35
|
+
Given create "Product" model with attributes as "hashes":
|
36
|
+
| code | price |
|
37
|
+
| 1 | |
|
38
|
+
| 2 | 0 |
|
39
|
+
| 3 | |
|
40
|
+
When filter "Product" by:
|
41
|
+
| field | value |
|
42
|
+
| price | [nil:] |
|
43
|
+
Then total records should be "2"
|
44
|
+
And records should have the following attributes:
|
45
|
+
| field | value |
|
46
|
+
| code | 1 |
|
47
|
+
| code | 3 |
|
48
|
+
|
49
|
+
Scenario: filter by several fields including both the hydra and general attributes
|
50
|
+
Given create "Product" model with attributes as "hashes":
|
51
|
+
| name | code | title | price | active | state | summary |
|
52
|
+
| toy | 1 | story | 2.40 | 1 | | |
|
53
|
+
| toy | 2 | story | 2.45 | 1 | | |
|
54
|
+
| toy | 3 | story | 2.45 | 1 | | |
|
55
|
+
| toy | 4 | | 2.45 | 0 | | |
|
56
|
+
| | 5 | | 2.45 | 1 | | |
|
57
|
+
| toy | 6 | | 2.46 | 1 | | |
|
58
|
+
When filter "Product" by:
|
59
|
+
| field | value |
|
60
|
+
| name | toy |
|
61
|
+
| title | story |
|
62
|
+
| summary | [nil:] |
|
63
|
+
| price | [float:2.45] |
|
64
|
+
| active | [bool:t] |
|
65
|
+
| state | [nil:] |
|
66
|
+
Then total records should be "2"
|
67
|
+
And records should have the following attributes:
|
68
|
+
| field | value |
|
69
|
+
| code | 2 |
|
70
|
+
| code | 3 |
|
@@ -0,0 +1,65 @@
|
|
1
|
+
Given /^create connection$/ do
|
2
|
+
spec = ActiveRecord::Base::ConnectionSpecification.new({database: ':memory:', adapter: 'sqlite3'}, 'sqlite3_connection')
|
3
|
+
@connection = ActiveRecord::ConnectionAdapters::ConnectionPool.new(spec).connection
|
4
|
+
end
|
5
|
+
|
6
|
+
Given /^(create|drop|migrate|rollback)(?:\sto|\sfrom)? hydra entity "([^"]+)"$/ do |method, table|
|
7
|
+
HydraAttribute::Migrator.send(method, @connection, table)
|
8
|
+
end
|
9
|
+
|
10
|
+
Given /^create table "([^"]+)"$/ do |table|
|
11
|
+
@connection.create_table(table)
|
12
|
+
end
|
13
|
+
|
14
|
+
Then /^should have the following (\d+) tables?:$/ do |count, table|
|
15
|
+
@connection.should have(count.to_i).tables
|
16
|
+
|
17
|
+
table.rows.flatten.each do |name|
|
18
|
+
@connection.tables.should include(name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Then /^should not have any tables$/ do
|
23
|
+
@connection.should have(0).tables
|
24
|
+
end
|
25
|
+
|
26
|
+
Then /^table "([^"]+)" should have the following (columns|indexes):$/ do |table_name, method, table|
|
27
|
+
connection_params = @connection.send(method, table_name).sort_by(&:name)
|
28
|
+
checked_params = table.hashes.map { |hash| type_cast_hash(hash) }.sort_by { |param| param['name'] }
|
29
|
+
|
30
|
+
unless connection_params.length == checked_params.length
|
31
|
+
raise %(Table "#{table_name}" has "#{connection_params.length}" #{method} but in our test "#{checked_params.length}". Diff: is "#{connection_params.map(&:name)}" but should be "#{checked_params.map { |h| h['name'] }}")
|
32
|
+
end
|
33
|
+
|
34
|
+
connection_params.zip(checked_params).each do |(real_params, params)|
|
35
|
+
params.keys.each do |name|
|
36
|
+
params[name].should == real_params.send(name)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
Then /^table "([^"]+)" should have (\d+) records?$/ do |table_name, count|
|
42
|
+
result = ActiveRecord::Base.connection.select_one("SELECT COUNT(*) AS count FROM #{table_name}")
|
43
|
+
result['count'].should == count.to_i
|
44
|
+
end
|
45
|
+
|
46
|
+
Then /^table "([^"]+)" should have (\d+) records?:$/ do |table_name, count, table|
|
47
|
+
step %(table "#{table_name}" should have #{count} records)
|
48
|
+
|
49
|
+
table.hashes.each do |hash|
|
50
|
+
table = Arel::Table.new(table_name, ActiveRecord::Base)
|
51
|
+
select = Arel.sql('COUNT(*)').as('count')
|
52
|
+
where = hash.map { |name, value| table[name].eq(type_cast_value(value)) }.inject(:and)
|
53
|
+
|
54
|
+
result = ActiveRecord::Base.connection.select_one(table.project(select).where(where))
|
55
|
+
unless result['count']
|
56
|
+
raise %(Query "#{table.project(select).where(where).to_sql}" return nil)
|
57
|
+
end
|
58
|
+
|
59
|
+
unless result['count'] == 1
|
60
|
+
raise %(Query "#{table.project(select).where(where).to_sql}" return "#{result['count']}")
|
61
|
+
end
|
62
|
+
result['count'].should be(1)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
@@ -6,6 +6,34 @@ Given /^create "([^"]+)" model$/ do |klass|
|
|
6
6
|
klass.constantize.create!
|
7
7
|
end
|
8
8
|
|
9
|
+
Given /^build "([^"]+)" model$/ do |klass|
|
10
|
+
@model = klass.constantize.new
|
11
|
+
end
|
12
|
+
|
13
|
+
Given /^build "([^"]+)" model:$/ do |klass, table|
|
14
|
+
@model = klass.constantize.new(type_cast_hash(table.rows_hash))
|
15
|
+
end
|
16
|
+
|
17
|
+
When /^set "([^"]+)" to "([^"]+)"$/ do |attribute, value|
|
18
|
+
@model.send("#{attribute}=", type_cast_value(value))
|
19
|
+
end
|
20
|
+
|
21
|
+
When /^(save|destroy) model$/ do |method|
|
22
|
+
@model.send(method)
|
23
|
+
end
|
24
|
+
|
25
|
+
When /^find "([^"]+)" model by attribute "([^"]+)" and value "([^"]+)"$/ do |class_name, attribute, value|
|
26
|
+
@model = class_name.constantize.send("find_by_#{attribute}", type_cast_value(value))
|
27
|
+
end
|
28
|
+
|
29
|
+
When /^find (first|last) "([^"]+)" model$/ do |method, class_name|
|
30
|
+
@model = class_name.constantize.send(method)
|
31
|
+
end
|
32
|
+
|
33
|
+
When /^reload model$/ do
|
34
|
+
@model.reload
|
35
|
+
end
|
36
|
+
|
9
37
|
Given /^create "([^"]+)" model with attributes as "([^"]+):"$/ do |klass, format, table|
|
10
38
|
Array.wrap(table.send(format)).each do |hash|
|
11
39
|
klass.constantize.create!(type_cast_hash(hash))
|
@@ -18,6 +46,26 @@ Given /^create hydra attributes for "([^"]+)" with role "([^"]+)" as "([^"]+)":$
|
|
18
46
|
end
|
19
47
|
end
|
20
48
|
|
49
|
+
Given /^create hydra sets for "([^"]+)" as "([^"]+)":$/ do |klass, format, table|
|
50
|
+
Array.wrap(table.send(format)).each do |hash|
|
51
|
+
step %(create hydra set "#{hash['name']}" for "#{klass}")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
Given /^create hydra set "([^"]+)" for "([^"]+)"$/ do |hydra_set_name, klass|
|
56
|
+
klass.constantize.hydra_sets.create!(name: type_cast_value(hydra_set_name))
|
57
|
+
end
|
58
|
+
|
59
|
+
Given /^add "([^"]+)" hydra attributes to hydra set:$/ do |klass, table|
|
60
|
+
klass = klass.constantize
|
61
|
+
|
62
|
+
Array.wrap(table.hashes).each do |hash|
|
63
|
+
Array.wrap(type_cast_value(hash['hydra set name'])).each do |set|
|
64
|
+
klass.hydra_sets.find_by_name(set).hydra_attributes << klass.hydra_attributes.find_by_name(type_cast_value(hash['hydra attribute name']))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
21
69
|
Given /^(load and )?(save|create|update(?: all| attributes)?|destroy(?: all)?|delete(?: all)?)(?: for)? "([^"]+)" models? with attributes as "([^"]+)":$/ do |load, action, klass, format, table|
|
22
70
|
action = action.gsub(' ', '_')
|
23
71
|
klass = klass.constantize
|
@@ -30,20 +78,45 @@ Given /^(load and )?(save|create|update(?: all| attributes)?|destroy(?: all)?|de
|
|
30
78
|
end
|
31
79
|
end
|
32
80
|
|
33
|
-
Then /^model
|
34
|
-
|
81
|
+
Then /^model (should(?:\snot)?) respond to "([^"]+)"$/ do |method, attributes|
|
82
|
+
method = method.gsub(/\s+/, '_')
|
83
|
+
attributes.split.each do |attribute|
|
84
|
+
@model.send(method, respond_to(attribute))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
Then /^model attributes (should(?:\snot)?) include "([^"]+)"$/ do |method, attributes|
|
35
89
|
method = method.gsub(/\s+/, '_')
|
36
90
|
attributes.split.each do |attribute|
|
37
|
-
model.send(method,
|
91
|
+
@model.attributes.keys.send(method, include(attribute))
|
38
92
|
end
|
39
93
|
end
|
40
94
|
|
41
|
-
Then /^(
|
42
|
-
|
43
|
-
|
95
|
+
Then /^model attributes (should(?:\snot)?) match "([^"]+)"$/ do |match, attribute|
|
96
|
+
@model.attributes.keys.send(match) =~ Array(type_cast_value(attribute))
|
97
|
+
end
|
98
|
+
|
99
|
+
Then /^model "([^"]+)" (should(?:\snot)?) respond to "([^"]+)"$/ do |klass, method, attributes|
|
100
|
+
@model = klass.constantize.new
|
101
|
+
step %(model #{method} respond to "#{attributes}")
|
102
|
+
end
|
103
|
+
|
104
|
+
Then /^error "([^"]+)" (should(?:\snot)?) be risen when methods? "([^"]+)" (?:is|are) called$/ do |error_class, expect, methods|
|
105
|
+
Array.wrap(methods.split).each do |method|
|
106
|
+
lambda { @model.send(method) }.send(expect.gsub(/\s+/, '_'), raise_error(error_class.constantize))
|
44
107
|
end
|
45
108
|
end
|
46
109
|
|
110
|
+
Then /^(last|first) created "([^"]+)" (should|should not) have the following attributes:$/ do |position, klass, match, table|
|
111
|
+
table.rows_hash.each do |attribute, value|
|
112
|
+
step %(#{position} created "#{klass}" #{match} have attribute "#{attribute}" with value "#{value}")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
Then /^(last|first) created "([^"]+)" (should|should not) have attribute "([^"]+)" with value "([^"]+)"$/ do |position, klass, match, attribute, value|
|
117
|
+
klass.constantize.send(position).send(attribute).send(match) == type_cast_value(value)
|
118
|
+
end
|
119
|
+
|
47
120
|
Then /^class "([^"]+)" (should(?:\snot)?) have "([^"]+)" in white list$/ do |klass, accept, attribute|
|
48
121
|
method = accept.sub(' ', '_')
|
49
122
|
klass.constantize.accessible_attributes.send(method, include(attribute))
|
@@ -5,7 +5,7 @@ end
|
|
5
5
|
|
6
6
|
When /^filter "([^"]+)" records by "([^"]+)"$/ do |klass, attribute|
|
7
7
|
@records = Object.const_get(klass)
|
8
|
-
step %
|
8
|
+
step %(filter records by "#{attribute}")
|
9
9
|
end
|
10
10
|
|
11
11
|
When /^filter records by "([^"]+)"$/ do |attribute|
|
@@ -15,7 +15,7 @@ end
|
|
15
15
|
|
16
16
|
When /^group "([^"]+)" by "([^"]+)"$/ do |klass, attributes|
|
17
17
|
@records = Object.const_get(klass)
|
18
|
-
step %
|
18
|
+
step %(group by "#{attributes}")
|
19
19
|
end
|
20
20
|
|
21
21
|
When /^group by "([^"]+)"$/ do |attributes|
|
@@ -24,7 +24,7 @@ end
|
|
24
24
|
|
25
25
|
When /^(order|reorder) "([^"]+)" records by "([^"]+)"$/ do |sort_method, klass, attributes|
|
26
26
|
@records = Object.const_get(klass)
|
27
|
-
step %
|
27
|
+
step %(#{sort_method} records by "#{attributes}")
|
28
28
|
end
|
29
29
|
|
30
30
|
When /^(order|reorder) records by "([^"]+)"$/ do |sort_method, attributes|
|
@@ -58,11 +58,10 @@ Then /^records should have only the following "([^"]+)" names$/ do |attributes|
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
Then /^records should raise "([^"]+)" when call the following "([^"]+)"$/ do |
|
62
|
-
error_class = error.constantize
|
61
|
+
Then /^records should raise "([^"]+)" when call the following "([^"]+)"$/ do |error_class, methods|
|
63
62
|
@records.each do |record|
|
64
63
|
methods.split(/\s+/).each do |method|
|
65
|
-
lambda { record.send(method) }.should raise_error(error_class)
|
64
|
+
lambda { record.send(method) }.should raise_error(error_class.constantize)
|
66
65
|
end
|
67
66
|
end
|
68
67
|
end
|
@@ -73,7 +72,7 @@ end
|
|
73
72
|
|
74
73
|
Then /^total "([^"]+)" records should be "([^"]+)"$/ do |klass, count|
|
75
74
|
@records = klass.constantize.scoped
|
76
|
-
step %
|
75
|
+
step %(total records should be "#{count}")
|
77
76
|
end
|
78
77
|
|
79
78
|
Then /^records "(should|should_not)" have loaded associations:$/ do |should, table|
|
data/features/support/env.rb
CHANGED
@@ -1,19 +1,33 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
require 'hydra_attribute'
|
3
3
|
require 'database_cleaner'
|
4
|
-
require 'database_cleaner/cucumber'
|
5
4
|
|
6
5
|
ActiveSupport.on_load(:active_record) do
|
7
6
|
self.default_timezone = :utc
|
8
|
-
unless ActiveRecord::VERSION::STRING.start_with?('3.1.')
|
7
|
+
unless ActiveRecord::VERSION::STRING.start_with?('3.1.') # @COMPATIBILITY with 3.1.x. active_record 3.1 doesn't have "mass_assignment_sanitizer" method
|
9
8
|
self.mass_assignment_sanitizer = :strict
|
10
9
|
end
|
11
|
-
|
10
|
+
|
11
|
+
ActiveRecord::Migration.send(:include, HydraAttribute::ActiveRecord::Migration)
|
12
12
|
end
|
13
13
|
|
14
14
|
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
15
15
|
DatabaseCleaner.strategy = :truncation
|
16
16
|
|
17
|
+
class Migration < ActiveRecord::Migration
|
18
|
+
def up
|
19
|
+
create_hydra_entity :products do |t|
|
20
|
+
t.string :name
|
21
|
+
t.timestamps
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def down
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Migration.new.up
|
30
|
+
|
17
31
|
Before do
|
18
32
|
redefine_hydra_entity('Product')
|
19
33
|
DatabaseCleaner.start
|
data/features/support/world.rb
CHANGED
@@ -3,15 +3,19 @@ module HydraAttribute
|
|
3
3
|
module World
|
4
4
|
def type_cast_value(schema)
|
5
5
|
return schema unless schema.is_a?(String)
|
6
|
-
type, value = schema.gsub(
|
6
|
+
type, value = schema.gsub(/(^\[)|(\]$)/, '').split(':', 2)
|
7
7
|
return schema if schema == type && value.nil?
|
8
8
|
|
9
9
|
case type
|
10
|
-
when '
|
11
|
-
when 'float'
|
12
|
-
when '
|
13
|
-
when 'nil'
|
14
|
-
when '
|
10
|
+
when 'int' then type_cast_value(value).to_i
|
11
|
+
when 'float' then type_cast_value(value).to_f
|
12
|
+
when 'bool' then ::ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(type_cast_value(value))
|
13
|
+
when 'nil' then nil
|
14
|
+
when 'date' then ActiveSupport::TimeZone.new('UTC').parse(type_cast_value(value))
|
15
|
+
when 'sym' then type_cast_value(value).to_sym
|
16
|
+
when 'array' then value.split(',').map { |v| type_cast_value(v) }
|
17
|
+
when 'eval' then eval(type_cast_value(value))
|
18
|
+
when 'str' then type_cast_value(value).to_s
|
15
19
|
else value
|
16
20
|
end
|
17
21
|
end
|
@@ -22,7 +26,8 @@ module HydraAttribute
|
|
22
26
|
end
|
23
27
|
|
24
28
|
def type_cast_attributes(attributes)
|
25
|
-
|
29
|
+
# 'a=[b c] c=a c=[v abc]' => ["a=[b c]", "c=a", "c=[v abc]"]
|
30
|
+
attributes.gsub(/\s+(\w+=)/, '<###>\1').split('<###>').each_with_object({}) do |attribute, hash|
|
26
31
|
name, value = type_cast_attribute(attribute)
|
27
32
|
hash[name] = value
|
28
33
|
end
|
@@ -39,15 +44,15 @@ module HydraAttribute
|
|
39
44
|
|
40
45
|
Object.send(:remove_const, klass.to_sym) if Object.const_defined?(klass.to_sym)
|
41
46
|
|
42
|
-
::HydraAttribute::
|
47
|
+
::HydraAttribute::SUPPORTED_BACKEND_TYPES.each do |type|
|
43
48
|
class_name = "Hydra#{type.capitalize}#{klass}".to_sym
|
44
49
|
::HydraAttribute.send(:remove_const, class_name) if ::HydraAttribute.const_defined?(class_name)
|
45
50
|
end
|
46
51
|
|
47
52
|
Object.const_set(klass.to_sym, Class.new(::ActiveRecord::Base))
|
48
53
|
klass.to_s.constantize.send(:accessible_attributes_configs).values.each(&:clear)
|
49
|
-
klass.to_s.constantize.attr_accessible :name
|
50
|
-
klass.to_s.constantize.
|
54
|
+
klass.to_s.constantize.attr_accessible :name, :hydra_set_id
|
55
|
+
klass.to_s.constantize.send(:include, ::HydraAttribute::ActiveRecord)
|
51
56
|
end
|
52
57
|
end
|
53
58
|
end
|
data/gemfiles/3.1.gemfile.lock
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
PATH
|
2
2
|
remote: /Users/kostyantyn/Sites/github/gems/hydra_attribute
|
3
3
|
specs:
|
4
|
-
hydra_attribute (0.
|
4
|
+
hydra_attribute (0.4.0.beta)
|
5
5
|
activerecord (>= 3.1.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activemodel (3.1.
|
11
|
-
activesupport (= 3.1.
|
10
|
+
activemodel (3.1.7)
|
11
|
+
activesupport (= 3.1.7)
|
12
12
|
builder (~> 3.0.0)
|
13
13
|
i18n (~> 0.6)
|
14
|
-
activerecord (3.1.
|
15
|
-
activemodel (= 3.1.
|
16
|
-
activesupport (= 3.1.
|
14
|
+
activerecord (3.1.7)
|
15
|
+
activemodel (= 3.1.7)
|
16
|
+
activesupport (= 3.1.7)
|
17
17
|
arel (~> 2.2.3)
|
18
18
|
tzinfo (~> 0.3.29)
|
19
|
-
activesupport (3.1.
|
19
|
+
activesupport (3.1.7)
|
20
20
|
multi_json (>= 1.0, < 1.3)
|
21
21
|
appraisal (0.4.1)
|
22
22
|
bundler
|
@@ -33,17 +33,17 @@ GEM
|
|
33
33
|
gherkin (2.11.1)
|
34
34
|
json (>= 1.4.6)
|
35
35
|
i18n (0.6.0)
|
36
|
-
json (1.7.
|
36
|
+
json (1.7.4)
|
37
37
|
multi_json (1.2.0)
|
38
38
|
rake (0.9.2.2)
|
39
|
-
rspec (2.
|
40
|
-
rspec-core (~> 2.
|
41
|
-
rspec-expectations (~> 2.
|
42
|
-
rspec-mocks (~> 2.
|
43
|
-
rspec-core (2.
|
44
|
-
rspec-expectations (2.
|
39
|
+
rspec (2.11.0)
|
40
|
+
rspec-core (~> 2.11.0)
|
41
|
+
rspec-expectations (~> 2.11.0)
|
42
|
+
rspec-mocks (~> 2.11.0)
|
43
|
+
rspec-core (2.11.1)
|
44
|
+
rspec-expectations (2.11.2)
|
45
45
|
diff-lcs (~> 1.1.3)
|
46
|
-
rspec-mocks (2.
|
46
|
+
rspec-mocks (2.11.1)
|
47
47
|
sqlite3 (1.3.6)
|
48
48
|
tzinfo (0.3.33)
|
49
49
|
|
data/gemfiles/3.2.gemfile.lock
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
PATH
|
2
2
|
remote: /Users/kostyantyn/Sites/github/gems/hydra_attribute
|
3
3
|
specs:
|
4
|
-
hydra_attribute (0.
|
4
|
+
hydra_attribute (0.4.0.beta)
|
5
5
|
activerecord (>= 3.1.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activemodel (3.2.
|
11
|
-
activesupport (= 3.2.
|
10
|
+
activemodel (3.2.7)
|
11
|
+
activesupport (= 3.2.7)
|
12
12
|
builder (~> 3.0.0)
|
13
|
-
activerecord (3.2.
|
14
|
-
activemodel (= 3.2.
|
15
|
-
activesupport (= 3.2.
|
13
|
+
activerecord (3.2.7)
|
14
|
+
activemodel (= 3.2.7)
|
15
|
+
activesupport (= 3.2.7)
|
16
16
|
arel (~> 3.0.2)
|
17
17
|
tzinfo (~> 0.3.29)
|
18
|
-
activesupport (3.2.
|
18
|
+
activesupport (3.2.7)
|
19
19
|
i18n (~> 0.6)
|
20
20
|
multi_json (~> 1.0)
|
21
21
|
appraisal (0.4.1)
|
@@ -33,17 +33,17 @@ GEM
|
|
33
33
|
gherkin (2.11.1)
|
34
34
|
json (>= 1.4.6)
|
35
35
|
i18n (0.6.0)
|
36
|
-
json (1.7.
|
36
|
+
json (1.7.4)
|
37
37
|
multi_json (1.3.6)
|
38
38
|
rake (0.9.2.2)
|
39
|
-
rspec (2.
|
40
|
-
rspec-core (~> 2.
|
41
|
-
rspec-expectations (~> 2.
|
42
|
-
rspec-mocks (~> 2.
|
43
|
-
rspec-core (2.
|
44
|
-
rspec-expectations (2.
|
39
|
+
rspec (2.11.0)
|
40
|
+
rspec-core (~> 2.11.0)
|
41
|
+
rspec-expectations (~> 2.11.0)
|
42
|
+
rspec-mocks (~> 2.11.0)
|
43
|
+
rspec-core (2.11.1)
|
44
|
+
rspec-expectations (2.11.2)
|
45
45
|
diff-lcs (~> 1.1.3)
|
46
|
-
rspec-mocks (2.
|
46
|
+
rspec-mocks (2.11.1)
|
47
47
|
sqlite3 (1.3.6)
|
48
48
|
tzinfo (0.3.33)
|
49
49
|
|
@@ -2,76 +2,112 @@ module HydraAttribute
|
|
2
2
|
module ActiveRecord
|
3
3
|
class Association < ::ActiveRecord::Associations::HasManyAssociation
|
4
4
|
|
5
|
-
def find_model(
|
5
|
+
def find_model(hydra_attribute_id)
|
6
6
|
load_target unless loaded?
|
7
|
-
|
8
|
-
|
7
|
+
|
8
|
+
hydra_set_target.detect do |model|
|
9
|
+
model.hydra_attribute_id == hydra_attribute_id
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
12
|
-
def find_model_or_build(
|
13
|
-
find_model(
|
13
|
+
def find_model_or_build(options = {})
|
14
|
+
find_model(options[:hydra_attribute_id]) || build(options)
|
14
15
|
end
|
15
16
|
|
16
17
|
def build(attributes = {}, options = {}, &block)
|
17
|
-
return if
|
18
|
+
return if hydra_attribute_ids.exclude?(attributes[:hydra_attribute_id])
|
19
|
+
return if target.any? { |model| model.hydra_attribute_id == attributes[:hydra_attribute_id] }
|
20
|
+
|
18
21
|
super
|
19
22
|
end
|
20
23
|
|
21
24
|
def all_models
|
22
25
|
unless @full_loaded
|
23
|
-
(
|
26
|
+
(hydra_attribute_ids - target.map(&:hydra_attribute_id)).each do |hydra_attribute_id|
|
24
27
|
build(hydra_attribute_id: hydra_attribute_id)
|
25
28
|
end
|
26
29
|
@full_loaded = true
|
27
30
|
end
|
28
|
-
|
31
|
+
hydra_set_target
|
29
32
|
end
|
30
33
|
|
31
|
-
def
|
32
|
-
|
34
|
+
def save
|
35
|
+
changed = false
|
36
|
+
all_models.each do |model|
|
37
|
+
model.entity_id = owner.id
|
38
|
+
model.save
|
39
|
+
changed = true unless model.previous_changes.blank?
|
40
|
+
end
|
41
|
+
changed
|
33
42
|
end
|
34
|
-
alias_method :locked_for_build?, :locked_for_build
|
35
43
|
|
36
|
-
def
|
37
|
-
@
|
38
|
-
@white_list_for_build = Array(white_list_for_build)
|
44
|
+
def lock!(white_list = [])
|
45
|
+
@white_list = Array(white_list)
|
39
46
|
loaded!
|
40
47
|
end
|
41
48
|
|
42
|
-
def
|
43
|
-
@
|
49
|
+
def hydra_attributes
|
50
|
+
if @white_list
|
51
|
+
@hydra_attributes ||= owner.class.hydra_set_attributes_for_backend_type(owner.hydra_set_id, reflection.backend_type)
|
52
|
+
else
|
53
|
+
owner.class.hydra_set_attributes_for_backend_type(owner.hydra_set_id, reflection.backend_type)
|
54
|
+
end
|
44
55
|
end
|
45
56
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
49
|
-
|
57
|
+
def hydra_attribute_ids
|
58
|
+
if @white_list
|
59
|
+
@hydra_attribute_ids ||= owner.class.hydra_set_attribute_ids_for_backend_type(owner.hydra_set_id, reflection.backend_type) & @white_list
|
60
|
+
else
|
61
|
+
owner.class.hydra_set_attribute_ids_for_backend_type(owner.hydra_set_id, reflection.backend_type)
|
62
|
+
end
|
50
63
|
end
|
51
64
|
|
52
|
-
|
65
|
+
def hydra_attribute_names
|
66
|
+
if @white_list
|
67
|
+
hydra_attributes.map(&:name)
|
68
|
+
else
|
69
|
+
owner.class.hydra_set_attribute_names_for_backend_type(owner.hydra_set_id, reflection.backend_type)
|
70
|
+
end
|
71
|
+
end
|
53
72
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
record
|
73
|
+
def hydra_set_target
|
74
|
+
@hydra_set_target ||= target.select do |model|
|
75
|
+
hydra_attribute_ids.include?(model.hydra_attribute_id)
|
76
|
+
end
|
59
77
|
end
|
60
78
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
79
|
+
def clear_cache!
|
80
|
+
@hydra_attributes = nil
|
81
|
+
@hydra_attribute_ids = nil
|
82
|
+
@full_loaded = nil
|
83
|
+
@hydra_set_target = nil
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
68
87
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
88
|
+
# Optimized method
|
89
|
+
# Remove unnecessary callbacks
|
90
|
+
def add_to_target(record)
|
91
|
+
@target << record
|
92
|
+
record
|
93
|
+
end
|
94
|
+
|
95
|
+
# Optimized method
|
96
|
+
# Attributes are written via low level function without additional checks
|
97
|
+
def build_record(options, _)
|
98
|
+
reflection.klass.new do |record|
|
99
|
+
unless options.has_key?(:value)
|
100
|
+
options[:value] = owner.class.hydra_attribute(options[:hydra_attribute_id]).default_value
|
101
|
+
end
|
102
|
+
|
103
|
+
record.send :write_attribute, 'id', options[:id]
|
104
|
+
record.send :write_attribute, 'entity_id', owner.id
|
105
|
+
record.send :write_attribute, 'hydra_attribute_id', options[:hydra_attribute_id]
|
106
|
+
record.send :write_attribute, 'value', options[:value]
|
107
|
+
|
108
|
+
hydra_set_target << record unless hydra_set_target.include?(record)
|
109
|
+
end
|
73
110
|
end
|
74
|
-
end
|
75
111
|
end
|
76
112
|
end
|
77
113
|
end
|