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.
- data/lib/custom_attributes.rb +22 -0
- data/lib/custom_attributes/controller.rb +20 -0
- data/lib/custom_attributes/custom_attribute.rb +11 -0
- data/lib/custom_attributes/custom_attribute_value.rb +6 -0
- data/lib/custom_attributes/has_custom_attributes.rb +136 -0
- data/lib/custom_attributes/version.rb +9 -0
- data/lib/generators/custom_attributes/install_generator.rb +22 -0
- data/lib/generators/custom_attributes/templates/create_custom_attributes.rb +27 -0
- data/lib/generators/custom_attributes/templates/custom_attributes.rb +18 -0
- data/test/custom_attributes_test.rb +7 -0
- data/test/test_helper.rb +3 -0
- metadata +76 -0
@@ -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,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,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
|
data/test/test_helper.rb
ADDED
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
|
+
|