custom_attributes 0.1.0

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.
@@ -0,0 +1,22 @@
1
+ # CustomAttributes
2
+
3
+ require 'custom_attributes/custom_attribute'
4
+ require 'custom_attributes/custom_attribute_value'
5
+ require 'custom_attributes/controller'
6
+ require 'custom_attributes/has_custom_attributes'
7
+ require 'custom_attributes/version'
8
+
9
+ module CustomAttributes
10
+ class << self
11
+ attr_accessor :scope
12
+ attr_accessor :scope_method
13
+ end
14
+ end
15
+
16
+ ActiveSupport.on_load(:active_record) do
17
+ include CustomAttributes::Model
18
+ end
19
+
20
+ ActiveSupport.on_load(:action_controller) do
21
+ include CustomAttributes::Controller
22
+ end
@@ -0,0 +1,20 @@
1
+ module CustomAttributes
2
+
3
+ module Controller
4
+ def self.included(base)
5
+ base.before_filter :set_custom_attribute_scope
6
+ end
7
+
8
+ # override me
9
+ def custom_attribute_scope
10
+ if method_name = ::CustomAttributes.scope_method
11
+ self.__send__(method_name)
12
+ end
13
+ end
14
+
15
+ def set_custom_attribute_scope
16
+ ::CustomAttributes.scope = custom_attribute_scope
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,11 @@
1
+ class ::CustomAttribute < ActiveRecord::Base
2
+ belongs_to :scope, :polymorphic => true
3
+ has_many :custom_attribute_values, :dependent => :destroy
4
+
5
+ def owner
6
+ attributes[:owner].try(:constantize)
7
+ end
8
+
9
+ validates_presence_of :name
10
+ validates_uniqueness_of :name, :scope => [:scope_type, :scope_id]
11
+ end
@@ -0,0 +1,6 @@
1
+ class ::CustomAttributeValue < ActiveRecord::Base
2
+ belongs_to :custom_attribute
3
+
4
+ validates_presence_of :value
5
+ validates_associated :custom_attribute
6
+ end
@@ -0,0 +1,136 @@
1
+ module CustomAttributes
2
+ module Model
3
+ module ClassMethods
4
+ def has_custom_attributes
5
+ self.__send__ :include, CustomAttributes::HasCustomAttributes
6
+ end
7
+ end
8
+
9
+ def self.included(receiver)
10
+ receiver.extend ClassMethods
11
+ end
12
+ end
13
+
14
+ module HasCustomAttributes
15
+ module ClassMethods
16
+ def custom_attributes
17
+ @custom_attributes ||= {}
18
+ @custom_attributes[::CustomAttributes.scope || :no_scope] ||= begin
19
+ arel = ::CustomAttribute.where(:owner => self.to_s)
20
+ if scope = ::CustomAttributes.scope
21
+ arel = arel.where(:scope_type => scope.class.to_s, :scope_id => scope.id)
22
+ else
23
+ arel = arel.where('scope_type IS NULL AND scope_id IS NULL')
24
+ end
25
+ arel
26
+ end
27
+ end
28
+
29
+ def add_custom_attribute(value_or_array)
30
+ case value_or_array
31
+ when ::CustomAttribute
32
+ value_or_array.owner = self.to_s
33
+ value_or_array.save
34
+ when Array
35
+ opts = {:scope => ::CustomAttributes.scope}
36
+ opts.merge!(value_or_array.pop) if value_or_array.last.is_a?(Hash)
37
+ value_or_array.each do |name|
38
+ add_custom_attribute ::CustomAttribute.new(opts.merge(:name => name))
39
+ end
40
+ when String, Symbol
41
+ add_custom_attribute [value_or_array]
42
+ else
43
+ raise "Uexpected values for custom_attributes <<: #{value_or_array.inspect}"
44
+ end
45
+ end
46
+ end
47
+
48
+ module InstanceMethods
49
+ def [](name)
50
+ custom_attributes[name] || super
51
+ end
52
+
53
+ def []=(name, value)
54
+ if custom_attribute_names.include?(name)
55
+ custom_attributes[name] = value
56
+ else
57
+ super
58
+ end
59
+ end
60
+
61
+ def attributes=(hash)
62
+ custom_attribute_names.each do |name|
63
+ if hash.keys.include?(name)
64
+ custom_attributes[name] = hash.delete(name)
65
+ end
66
+ end
67
+ end
68
+
69
+ def attributes
70
+ super.merge custom_attributes
71
+ end
72
+
73
+ def custom_attributes
74
+ @custom_attributes ||= {}
75
+ @custom_attributes[::CustomAttributes.scope || :no_scope] ||= begin
76
+ all_attributes = self.class.custom_attributes
77
+ all_attributes.inject({}) do |attribs, custom_attrib|
78
+ # FIXME: should NOT make a separate request to the db for each value
79
+ attribs[custom_attrib.name] = read_custom_attribute(custom_attrib.name)
80
+ attribs
81
+ end
82
+ end
83
+ end
84
+
85
+ def custom_attribute_names
86
+ self.class.custom_attributes.map(&:name)
87
+ end
88
+
89
+ def method_missing(meth, *args, &blk)
90
+ name = meth.to_s.gsub(/\=$/, '')
91
+ if custom_attribute_names.include?(name)
92
+ if meth =~ /\=$/
93
+ self[name] = args.first
94
+ else
95
+ self[name] || read_custom_attribute(name)
96
+ end
97
+ else
98
+ super
99
+ end
100
+ end
101
+
102
+ private
103
+
104
+ def attribute_values(name)
105
+ custom_attribute = self.class.custom_attributes.where(:name => name).first
106
+ custom_attribute.custom_attribute_values
107
+ end
108
+
109
+ def read_custom_attribute(name)
110
+ attribute_values(name).where(:owner_id => self.id).first.try(:value)
111
+ end
112
+
113
+ def write_custom_attribute(name, value)
114
+ values = attribute_values(name)
115
+ existing_value = values.where(:owner_id => self.id).first
116
+ if existing_value
117
+ existing_value.update_attribute(:value, value)
118
+ else
119
+ values.create(:owner_id => self.id, :value => value)
120
+ end
121
+ end
122
+
123
+ def write_custom_attributes_from_hash
124
+ custom_attributes.each do |name, value|
125
+ write_custom_attribute(name, value)
126
+ end
127
+ end
128
+ end
129
+
130
+ def self.included(receiver)
131
+ receiver.extend ClassMethods
132
+ receiver.__send__ :include, InstanceMethods
133
+ receiver.after_save :write_custom_attributes_from_hash
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,9 @@
1
+ module CustomAttributes
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ BUILD = 0
6
+
7
+ STRING = [MAJOR, MINOR, BUILD].join('.')
8
+ end
9
+ end
@@ -0,0 +1,22 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+ require 'rails/generators/active_record/migration'
4
+
5
+ module CustomAttributes
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+ extend ActiveRecord::Generators::Migration
9
+
10
+ source_root File.expand_path('../templates', __FILE__)
11
+
12
+ desc 'Generates (but does not run) a migration to add the custom_attributes table.'
13
+
14
+ def copy_files
15
+ template 'custom_attributes.rb', 'config/initializers/custom_attributes.rb'
16
+ end
17
+
18
+ def create_migration_file
19
+ migration_template 'create_custom_attributes.rb', 'db/migrate/create_custom_attributes.rb'
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ class CreateCustomAttributes < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :custom_attributes do |t|
4
+ t.string :name
5
+ t.string :owner
6
+ t.string :scope_type
7
+ t.string :scope_id
8
+ t.timestamps
9
+ end
10
+ add_index :custom_attributes, [:scope_type, :scope_id]
11
+
12
+ create_table :custom_attribute_values do |t|
13
+ t.integer :custom_attribute_id
14
+ t.string :owner_id
15
+ t.string :value
16
+ t.timestamps
17
+ end
18
+ add_index :custom_attribute_values, :custom_attribute_id
19
+ end
20
+
21
+ def self.down
22
+ remove_index :custom_attributes, [:item_type, :item_id]
23
+ drop_table :custom_attributes
24
+ remove_index :custom_attribute_values, [:custom_attribute_id]
25
+ drop_table :custom_attribute_values
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ # Add scope by defining which controller method returns it:
2
+ #
3
+ # ::CustomAttributes.scope_method = :current_user
4
+ #
5
+ # Or set the scope object directly:
6
+ #
7
+ # ::CustomAttributes.scope = User.first
8
+ #
9
+ # Or override the controller method that returns the scope:
10
+ #
11
+ # class ApplicationController < ActionController::Base
12
+ # def custom_attribute_scope
13
+ # # scope determination
14
+ # if current_user.can?(:customize, resource)
15
+ # current_user
16
+ # end
17
+ # end
18
+ # end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class CustomAttributesTest < ActiveSupport::TestCase
4
+ # test "the truth" do
5
+ # assert true
6
+ # end
7
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'active_support'
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: custom_attributes
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - "Ren\xC3\xA9 F\xC3\xB6hring"
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-18 00:00:00 +02:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rails
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: "3"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ description: CustomAttributes allows you to add custom attributes to ActiveRecord objects, optionally scoped by another model (e.g. users).
28
+ email: rf@bamaru.de
29
+ executables: []
30
+
31
+ extensions: []
32
+
33
+ extra_rdoc_files: []
34
+
35
+ files:
36
+ - lib/custom_attributes/controller.rb
37
+ - lib/custom_attributes/custom_attribute.rb
38
+ - lib/custom_attributes/custom_attribute_value.rb
39
+ - lib/custom_attributes/has_custom_attributes.rb
40
+ - lib/custom_attributes/version.rb
41
+ - lib/custom_attributes.rb
42
+ - lib/generators/custom_attributes/install_generator.rb
43
+ - lib/generators/custom_attributes/templates/create_custom_attributes.rb
44
+ - lib/generators/custom_attributes/templates/custom_attributes.rb
45
+ - test/custom_attributes_test.rb
46
+ - test/test_helper.rb
47
+ has_rdoc: true
48
+ homepage: http://github.com/rrrene/custom_attributes
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options: []
53
+
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ requirements:
69
+ - none
70
+ rubyforge_project:
71
+ rubygems_version: 1.6.2
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: CustomAttributes allows you to add custom attributes to ActiveRecord objects, optionally scoped by another model (e.g. users).
75
+ test_files: []
76
+