eav_presenter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+