eav_presenter 0.0.1

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.
Files changed (2) hide show
  1. data/lib/eav_presenter.rb +94 -0
  2. metadata +67 -0
@@ -0,0 +1,94 @@
1
+ # Usage:
2
+ # Say you have an eav design pattern like this: Person, PersonAttribute and PersonAttrValue
3
+ # You can then define a new class:
4
+ # class EavPerson < Person
5
+ # include EavPresenter
6
+ # eav :eav_attr_class => PersonAttribute, :eav_value_class => PersonAttrValue, :eav_entity_foreign_key => "personId",
7
+ # :eav_attr_foreign_key => "attrId"
8
+ # end
9
+ #
10
+ # The attributes in PersonAttribute will now behave as DB columns. You can also use AR validation macros on them
11
+ # Dirty-tracking will not work in this case. Should be possible to implement.
12
+ # I have tested such a presenter model with scaffolding_extensions plugin only. More testing would be nice.
13
+
14
+ module EavPresenter
15
+ def self.included(base)
16
+ base.send(:extend, ClassMethods)
17
+ end
18
+
19
+ def load_eav_attr_values_if_not_loaded
20
+ entity_foreign_key = self.class.instance_variable_get("@eav_entity_foreign_key")
21
+ @eav_attr_values ||= self.class.instance_variable_get("@eav_value_class").send("find_all_by_#{entity_foreign_key}",self.id)
22
+ end
23
+
24
+ def save_eav_attr_values
25
+ self.class.instance_variable_get("@eav_attrs").each { |at|
26
+ eavs = load_eav_attr_values_if_not_loaded
27
+ eav = eavs.find { |i| i.attrId == at.id } #eav in the db
28
+ name = at.eav_attr_name
29
+ entity_foreign_key = self.class.instance_variable_get("@eav_entity_foreign_key")
30
+ attr_foreign_key = self.class.instance_variable_get("@eav_attr_foreign_key")
31
+ eav_value_class = self.class.instance_variable_get("@eav_value_class")
32
+ ivalue = send(name)
33
+ if attribute_changed?(name)
34
+ if eav
35
+ if ivalue.blank?
36
+ #eav needs to be deleted
37
+ eav_value_class.send("find_by_#{attr_foreign_key}_and_#{entity_foreign_key}",at.id,self.id).destroy
38
+ else
39
+ # eav has been modified. needs to be saved.
40
+ eav.value = ivalue
41
+ eav.save!
42
+ end
43
+ else
44
+ #eav needs to be created
45
+ eav_value_class.create({entity_foreign_key.to_sym => self.id, attr_foreign_key.to_sym => at.id, :value => ivalue})
46
+ end
47
+ end
48
+ }
49
+ self.reload # Values have been changed in DB. Better reload them.
50
+ @eav_attr_values = nil
51
+ load_eav_attr_values_if_not_loaded
52
+ end
53
+
54
+ module ClassMethods
55
+ def eav(opts)
56
+ @eav_attr_class = opts[:eav_attr_class]
57
+ @eav_value_class = opts[:eav_value_class]
58
+ @eav_entity_foreign_key = opts[:eav_entity_foreign_key]
59
+ @eav_attr_foreign_key = opts[:eav_attr_foreign_key]
60
+ @eav_attrs = @eav_attr_class.all
61
+
62
+ define_method(:attributes) {
63
+ super.merge(Hash[self.class.instance_variable_get("@eav_attrs").map(&:eav_attr_name).map { |name| [name, send(name)] }])
64
+ }
65
+ # define_attribute_methods(@eav_attrs.collect(&:eav_attr_name))
66
+
67
+ @eav_attrs.each { |at|
68
+ define_method(at.eav_attr_name) { |*args|
69
+ eavs = load_eav_attr_values_if_not_loaded
70
+ if instance_variables.include?("@#{at.eav_attr_name}")
71
+ instance_variable_get("@#{at.eav_attr_name}")
72
+ else
73
+ eavs.find { |i| i.attrId == at.id }.try(:value)
74
+ end
75
+ }
76
+
77
+ define_method("#{at.eav_attr_name}=") { |value|
78
+ raise "EAV value for #{at.eav_attr_name} must be a string or nil" unless value.nil? || value.is_a?(String)
79
+ eavs = load_eav_attr_values_if_not_loaded
80
+ instance_variable_set("@#{at.eav_attr_name}",value)
81
+ old = eavs.find { |i| i.attrId == at.id }.try(:value)
82
+ if value == old
83
+ changed_attributes.delete(at.eav_attr_name)
84
+ else
85
+ changed_attributes[at.eav_attr_name] = old
86
+ end
87
+ }
88
+ }
89
+ after_save :save_eav_attr_values # Register a callback which makes sure that any changes made are sync'ed to the AttrValues table
90
+ after_find :load_eav_attr_values_if_not_loaded
91
+ end
92
+ end
93
+ end
94
+
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eav_presenter
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Nilesh Trivedi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-10-30 00:00:00 +05:30
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: activerecord
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ description: ActiveRecord model like presenter for Entity-Attribute-Value pattern
28
+ email:
29
+ - github@nileshtrivedi.com
30
+ executables: []
31
+
32
+ extensions: []
33
+
34
+ extra_rdoc_files: []
35
+
36
+ files:
37
+ - lib/eav_presenter.rb
38
+ has_rdoc: true
39
+ homepage: http://github.com/nileshtrivedi/eav_presenter
40
+ licenses: []
41
+
42
+ post_install_message:
43
+ rdoc_options: []
44
+
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.5.1
63
+ signing_key:
64
+ specification_version: 3
65
+ summary: ActiveRecord model like presenter for Entity-Attribute-Value pattern
66
+ test_files: []
67
+