ee_preferences 0.4.3
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.
- checksums.yaml +15 -0
- data/.gitignore +8 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.rdoc +85 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +224 -0
- data/Rakefile +36 -0
- data/app/models/preference.rb +65 -0
- data/generators/preferences/USAGE +5 -0
- data/generators/preferences/preferences_generator.rb +7 -0
- data/generators/preferences/templates/001_create_preferences.rb +16 -0
- data/init.rb +1 -0
- data/lib/preferences/preference_definition.rb +56 -0
- data/lib/preferences/version.rb +3 -0
- data/lib/preferences.rb +616 -0
- data/preferences.gemspec +20 -0
- data/test/app_root/app/models/car.rb +2 -0
- data/test/app_root/app/models/employee.rb +2 -0
- data/test/app_root/app/models/manager.rb +3 -0
- data/test/app_root/app/models/user.rb +8 -0
- data/test/app_root/db/migrate/001_create_users.rb +11 -0
- data/test/app_root/db/migrate/002_create_cars.rb +11 -0
- data/test/app_root/db/migrate/003_create_employees.rb +12 -0
- data/test/app_root/db/migrate/004_migrate_preferences_to_version_1.rb +13 -0
- data/test/factory.rb +65 -0
- data/test/functional/preferences_test.rb +1364 -0
- data/test/test_helper.rb +26 -0
- data/test/unit/preference_definition_test.rb +237 -0
- data/test/unit/preference_test.rb +236 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NDc1NTg2MzkyYmYxMGRmMDgxNzY0M2EyYTRmMTczYThlZTgxN2IxNg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
Njk2N2U0OTBmYWY2NjVkM2Y5N2NhNzIxNjZmMWRjOWUyN2I4ZjZjMg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
Mjc5MmQ5MmYwYzhhNWVmOGMyMmY5NTEwNDI1OThhNDMxNWFkYzRmNjdlNGI4
|
10
|
+
YjkxNjJhZDU0M2NiMTIyMzU5Mzg5ZjFlNzQwMGUyMWJiY2M2ZTBkNDIxZTZm
|
11
|
+
Y2NiODY3N2M1NmY2ZWM5NjA3NDAwNmRjYjk1MGJlODJlOGIyNDA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MWUxY2M4MTM4MTU4ZTc0NmQ0ZGUxMTZhMWIyMWM4NTkxYmJhN2M0OTczNGIz
|
14
|
+
ZjcyOGQxMGE5YTdlZGU3MDUwMDYzZmI5ZGQ4Y2MwNGE5ODQ3NjZlMzAxODE1
|
15
|
+
ZjhkZWEyZjY1MDQzYWFjOGI2YmJiMjVjMzc1YjZlNTMxMjAwMGI=
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
== master
|
2
|
+
== 0.4.3 / 2014-09-08
|
3
|
+
|
4
|
+
* Fix #named_scope to #scope
|
5
|
+
|
6
|
+
== 0.4.2 / 2010-04-17
|
7
|
+
|
8
|
+
* Fix #preferences lookup not typecasting values
|
9
|
+
|
10
|
+
== 0.4.1 / 2010-03-07
|
11
|
+
|
12
|
+
* Add support for per-group default preferences
|
13
|
+
* Fix unsaved boolean preferences getting overridden by defaults if value is false
|
14
|
+
|
15
|
+
== 0.4.0 / 2010-03-07
|
16
|
+
|
17
|
+
* Add {preference}_changed?, {preference}_was, {preference}_changed, {preference}_will_change!, and reset_{preference}!
|
18
|
+
* Add #preferences_changed?, #preferences_changed, and #preference_changes
|
19
|
+
* Fix preferences that are reverted externally still getting stored
|
20
|
+
* Fix preference definition types not being used to typecast values
|
21
|
+
* No longer allow both group and non-group preferences to be looked up at once (except for named scopes)
|
22
|
+
* Add support for using Symbols to reference groups
|
23
|
+
* Fix #reload not causing unsaved preferences to get reset
|
24
|
+
* Raise exception if unknown preference is accessed
|
25
|
+
* Rename #set_preference to #write_preference
|
26
|
+
* Add caching of preference lookups
|
27
|
+
* Fix preferences being stored even if they didn't change
|
28
|
+
* Release gems via rake-gemcutter instead of rubyforge
|
29
|
+
* Add a generator for db migration to make installation a bit easier [Tim Lowrimore]
|
30
|
+
* Add named scopes: #with_preferences and #without_preferences
|
31
|
+
|
32
|
+
== 0.3.1 / 2009-04-25
|
33
|
+
|
34
|
+
* Rename Preference#attribute to #name to avoid conflicts with reserved methods in ActiveRecord
|
35
|
+
|
36
|
+
== 0.3.0 / 2009-04-13
|
37
|
+
|
38
|
+
* Add dependency on Rails 2.3
|
39
|
+
* Remove dependency on plugins_plus
|
40
|
+
|
41
|
+
== 0.2.0 / 2008-12-14
|
42
|
+
|
43
|
+
* Remove the PluginAWeek namespace
|
44
|
+
|
45
|
+
== 0.1.5 / 2008-11-16
|
46
|
+
|
47
|
+
* Add all prefers/preferred accessors for preferences to be analogous to ActiveRecord column accessors
|
48
|
+
* Fix preferences defined in STI subclasses not working [Quinn Shanahan]
|
49
|
+
|
50
|
+
== 0.1.4 / 2008-10-26
|
51
|
+
|
52
|
+
* Change how the base module is included to prevent namespacing conflicts
|
53
|
+
|
54
|
+
== 0.1.3 / 2008-06-29
|
55
|
+
|
56
|
+
* Add +prefs+ as an alias for +preferences+
|
57
|
+
* Fix +preferences+ not properly selecting preferences when a group is specified
|
58
|
+
* Improve test coverage
|
59
|
+
|
60
|
+
== 0.1.2 / 2008-06-22
|
61
|
+
|
62
|
+
* Remove log files from gems
|
63
|
+
|
64
|
+
== 0.1.1 / 2008-06-20
|
65
|
+
|
66
|
+
* Rename preference_values hash to preferences
|
67
|
+
* Rename preferences association to stored_preferences
|
68
|
+
|
69
|
+
== 0.1.0 / 2008-06-19
|
70
|
+
|
71
|
+
* Avoid string evaluation for dynamic methods
|
72
|
+
* Return hashes for the preference_values, e.g.
|
73
|
+
|
74
|
+
user.preference_values # => {'color' => 'red', 'number' => 11, 'website' => {'background' => 'white', 'foreground' => 'black'}}
|
75
|
+
user.preference_values('website') # => {'background' => 'white', 'foreground' => 'black'}
|
76
|
+
|
77
|
+
* Add more generic grouping of preferences than with just other records, e.g.
|
78
|
+
|
79
|
+
user.preferred_color('cars')
|
80
|
+
|
81
|
+
* Remove support for an options hash when specifying :for associations for preference
|
82
|
+
|
83
|
+
== 0.0.1 / 2008-05-10
|
84
|
+
|
85
|
+
* Initial public release
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008-2009 Aaron Pfeifer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
== preferences http://travis-ci.org/pluginaweek/preferences.png
|
2
|
+
|
3
|
+
+preferences+ adds support for easily creating custom preferences for models.
|
4
|
+
|
5
|
+
== Resources
|
6
|
+
|
7
|
+
API
|
8
|
+
|
9
|
+
* http://rdoc.info/github/pluginaweek/preferences/master/frames
|
10
|
+
|
11
|
+
Bugs
|
12
|
+
|
13
|
+
* http://github.com/pluginaweek/preferences/issues
|
14
|
+
|
15
|
+
Development
|
16
|
+
|
17
|
+
* http://github.com/pluginaweek/preferences
|
18
|
+
|
19
|
+
Testing
|
20
|
+
|
21
|
+
* http://travis-ci.org/pluginaweek/preferences
|
22
|
+
|
23
|
+
Source
|
24
|
+
|
25
|
+
* git://github.com/pluginaweek/preferences.git
|
26
|
+
|
27
|
+
Mailing List
|
28
|
+
|
29
|
+
* http://groups.google.com/group/pluginaweek-talk
|
30
|
+
|
31
|
+
== Description
|
32
|
+
|
33
|
+
Preferences for models within an application, such as for users, is a pretty
|
34
|
+
common idiom. Although the rule of thumb is to keep the number of preferences
|
35
|
+
available to a minimum, sometimes it's necessary if you want users to be able to
|
36
|
+
disable things like e-mail notifications.
|
37
|
+
|
38
|
+
Generally, basic preferences can be accomplished through simple designs, such as
|
39
|
+
additional columns or a bit vector described and implemented by preference_fu[http://agilewebdevelopment.com/plugins/preferencefu].
|
40
|
+
However, as you find the need for non-binary preferences and the number of
|
41
|
+
preferences becomes unmanageable as individual columns in the database, the next
|
42
|
+
step is often to create a separate "preferences" table. This is where the
|
43
|
+
+preferences+ plugin comes in.
|
44
|
+
|
45
|
+
+preferences+ encapsulates this design by exposing preferences using simple
|
46
|
+
attribute accessors on the model, hiding the fact that preferences are stored in
|
47
|
+
a separate table and making it dead-simple to define and manage preferences.
|
48
|
+
|
49
|
+
== Usage
|
50
|
+
|
51
|
+
=== Installation
|
52
|
+
|
53
|
+
+preferences+ requires an additional database table to work. You can generate
|
54
|
+
a migration for this table like so:
|
55
|
+
|
56
|
+
script/generate preferences
|
57
|
+
|
58
|
+
Then simply migrate your database:
|
59
|
+
|
60
|
+
rake db:migrate
|
61
|
+
|
62
|
+
=== Defining preferences
|
63
|
+
|
64
|
+
To define the preferences for a model, you can do so right within the model:
|
65
|
+
|
66
|
+
class User < ActiveRecord::Base
|
67
|
+
preference :hot_salsa
|
68
|
+
preference :dark_chocolate, :default => true
|
69
|
+
preference :color, :string
|
70
|
+
preference :favorite_number
|
71
|
+
preference :language, :string, :default => 'English', :group_defaults => {:chat => 'Spanish'}
|
72
|
+
end
|
73
|
+
|
74
|
+
In the above model, 5 preferences have been defined:
|
75
|
+
* hot_salsa
|
76
|
+
* dark_chocolate
|
77
|
+
* color
|
78
|
+
* favorite_number
|
79
|
+
* language
|
80
|
+
|
81
|
+
For each preference, a data type and default value can be specified. If no
|
82
|
+
data type is given, it's assumed to be a boolean value. If no default value is
|
83
|
+
given, the default is assumed to be nil.
|
84
|
+
|
85
|
+
=== Accessing preferences
|
86
|
+
|
87
|
+
Once preferences have been defined for a model, they can be accessed either
|
88
|
+
using the accessor methods that are generated for each preference or the generic
|
89
|
+
methods that are not specific to a particular preference.
|
90
|
+
|
91
|
+
==== Accessors
|
92
|
+
|
93
|
+
There are several shortcut methods that are generated for each preference
|
94
|
+
defined on a model. These reflect the same set of methods (attribute accessors)
|
95
|
+
that are generated for a model's columns. Examples of these are shown below:
|
96
|
+
|
97
|
+
Query methods:
|
98
|
+
user.prefers_hot_salsa? # => false
|
99
|
+
user.preferred_language? # => true
|
100
|
+
|
101
|
+
Reader methods:
|
102
|
+
user.prefers_hot_salsa # => false
|
103
|
+
user.preferred_language # => "English"
|
104
|
+
|
105
|
+
Writer methods:
|
106
|
+
user.prefers_hot_salsa = false # => false
|
107
|
+
user.preferred_language = 'English' # => "English"
|
108
|
+
|
109
|
+
==== Generic methods
|
110
|
+
|
111
|
+
Each preference accessor is essentially a wrapper for the various generic methods
|
112
|
+
shown below:
|
113
|
+
|
114
|
+
Query method:
|
115
|
+
user.prefers?(:hot_salsa) # => false
|
116
|
+
user.preferred?(:language) # => true
|
117
|
+
|
118
|
+
Reader method:
|
119
|
+
user.prefers(:hot_salsa) # => false
|
120
|
+
user.preferred(:language) # => "English"
|
121
|
+
|
122
|
+
Write method:
|
123
|
+
user.write_preference(:hot_salsa, false) # => false
|
124
|
+
user.write_preference(:language, "English") # => "English"
|
125
|
+
|
126
|
+
=== Accessing all preferences
|
127
|
+
|
128
|
+
To get the collection of all custom, stored preferences for a particular record,
|
129
|
+
you can access the +stored_preferences+ has_many association which is automatically
|
130
|
+
generated:
|
131
|
+
|
132
|
+
user.stored_preferences
|
133
|
+
|
134
|
+
In addition to this, you can get a hash of all stored preferences *and* default
|
135
|
+
preferences, by accessing the +preferences+ helper:
|
136
|
+
|
137
|
+
user.preferences # => {"language"=>"English", "color"=>nil}
|
138
|
+
|
139
|
+
This hash will contain the value for every preference that has been defined for
|
140
|
+
the model, whether that's the default value or one that has been previously
|
141
|
+
stored.
|
142
|
+
|
143
|
+
A short-hand alternative for preferences is also available:
|
144
|
+
|
145
|
+
user.prefs # => {"language"=>"English", "color"=>nil}
|
146
|
+
|
147
|
+
=== Grouping preferences
|
148
|
+
|
149
|
+
In addition to defining generic preferences for the owning record, you can also
|
150
|
+
group preferences by ActiveRecord objects or arbitrary names. This is best shown
|
151
|
+
through an example:
|
152
|
+
|
153
|
+
user = User.find(:first)
|
154
|
+
car = Car.find(:first)
|
155
|
+
|
156
|
+
user.preferred_color = 'red', car
|
157
|
+
# user.write_preference(:color, 'red', car) # The generic way
|
158
|
+
|
159
|
+
This will create a color preference of "red" for the given car. In this way,
|
160
|
+
you can have "color" preferences for different records.
|
161
|
+
|
162
|
+
To access the preference for a particular record, you can use the same accessor
|
163
|
+
methods as before:
|
164
|
+
|
165
|
+
user.preferred_color(car)
|
166
|
+
# user.preferred(:color, car) # The generic way
|
167
|
+
|
168
|
+
In addition to grouping preferences for a particular record, you can also group
|
169
|
+
preferences by name. For example,
|
170
|
+
|
171
|
+
user = User.find(:first)
|
172
|
+
|
173
|
+
user.preferred_color = 'red', :automobiles
|
174
|
+
user.preferred_color = 'tan', :clothing
|
175
|
+
|
176
|
+
user.preferred_color(:automobiles) # => "red"
|
177
|
+
user.preferred_color(:clothing) # => "tan"
|
178
|
+
|
179
|
+
user.preferences(:automobiles) # => {"color"=>"red"}
|
180
|
+
|
181
|
+
=== Saving preferences
|
182
|
+
|
183
|
+
Note that preferences are not saved until the owning record is saved.
|
184
|
+
Preferences are treated in a similar fashion to attributes. For example,
|
185
|
+
|
186
|
+
user = user.find(:first)
|
187
|
+
user.attributes = {:prefers_hot_salsa => false, :preferred_color => 'red'}
|
188
|
+
user.save!
|
189
|
+
|
190
|
+
Preferences are stored in a separate table called "preferences".
|
191
|
+
|
192
|
+
=== Tracking changes
|
193
|
+
|
194
|
+
Similar to ActiveRecord attributes, unsaved changes to preferences can be
|
195
|
+
tracked. For example,
|
196
|
+
|
197
|
+
user.preferred_language # => "English"
|
198
|
+
user.preferred_language_changed? # => false
|
199
|
+
user.preferred_language = 'Spanish'
|
200
|
+
user.preferred_language_changed? # => true
|
201
|
+
user.preferred_language_was # => "English"
|
202
|
+
user.preferred_language_change # => ["English", "Spanish"]
|
203
|
+
user.reset_preferred_language!
|
204
|
+
user.preferred_language # => "English"
|
205
|
+
|
206
|
+
Assigning the same value leaves the preference unchanged:
|
207
|
+
|
208
|
+
user.preferred_language # => "English"
|
209
|
+
user.preferred_language = 'English'
|
210
|
+
user.preferred_language_changed? # => false
|
211
|
+
user.preferred_language_change # => nil
|
212
|
+
|
213
|
+
== Testing
|
214
|
+
|
215
|
+
Before you can run any tests, the following gem must be installed:
|
216
|
+
* plugin_test_helper[http://github.com/pluginaweek/plugin_test_helper]
|
217
|
+
|
218
|
+
To run against a specific version of Rails:
|
219
|
+
|
220
|
+
rake test RAILS_FRAMEWORK_ROOT=/path/to/rails
|
221
|
+
|
222
|
+
== Dependencies
|
223
|
+
|
224
|
+
* Rails 2.3 or later
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
|
6
|
+
desc 'Default: run all tests.'
|
7
|
+
task :default => :test
|
8
|
+
|
9
|
+
desc "Test preferences."
|
10
|
+
Rake::TestTask.new(:test) do |t|
|
11
|
+
t.libs << 'lib'
|
12
|
+
t.test_files = Dir['test/**/*_test.rb']
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
begin
|
17
|
+
require 'rcov/rcovtask'
|
18
|
+
namespace :test do
|
19
|
+
desc "Test preferences with Rcov."
|
20
|
+
Rcov::RcovTask.new(:rcov) do |t|
|
21
|
+
t.libs << 'lib'
|
22
|
+
t.test_files = Dir['test/**/*_test.rb']
|
23
|
+
t.rcov_opts << '--exclude="^(?!lib/|app/)"'
|
24
|
+
t.verbose = true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
rescue LoadError
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Generate documentation for preferences."
|
31
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
32
|
+
rdoc.rdoc_dir = 'rdoc'
|
33
|
+
rdoc.title = 'preferences'
|
34
|
+
rdoc.options << '--line-numbers' << '--inline-source' << '--main=README.rdoc'
|
35
|
+
rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc', 'LICENSE', 'lib/**/*.rb', 'app/**/*.rb')
|
36
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Represents a preferred value for a particular preference on a model.
|
2
|
+
#
|
3
|
+
# == Grouped preferences
|
4
|
+
#
|
5
|
+
# In addition to simple named preferences, preferences can also be grouped by
|
6
|
+
# a particular value, be it a string or ActiveRecord object. For example, a
|
7
|
+
# User may have a preferred color for a particular Car. In this case, the
|
8
|
+
# +owner+ is the User record, the +name+ is "color", and the +group+ is the
|
9
|
+
# Car record. This allows preferences to have a sort of context around them.
|
10
|
+
class Preference < ActiveRecord::Base
|
11
|
+
belongs_to :owner, :polymorphic => true
|
12
|
+
belongs_to :group, :polymorphic => true
|
13
|
+
|
14
|
+
validates_presence_of :name, :owner_id, :owner_type
|
15
|
+
validates_presence_of :group_type, :if => :group_id?
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Splits the given group into its corresponding id and type. For simple
|
19
|
+
# primitives, the id will be nil. For complex types, specifically
|
20
|
+
# ActiveRecord objects, the id is the unique identifier stored in the
|
21
|
+
# database for the record.
|
22
|
+
#
|
23
|
+
# For example,
|
24
|
+
#
|
25
|
+
# Preference.split_group('google') # => [nil, "google"]
|
26
|
+
# Preference.split_group(1) # => [nil, 1]
|
27
|
+
# Preference.split_group(User.find(1)) # => [1, "User"]
|
28
|
+
def split_group(group = nil)
|
29
|
+
if group.is_a?(ActiveRecord::Base)
|
30
|
+
group_id, group_type = group.id, group.class.base_class.name.to_s
|
31
|
+
else
|
32
|
+
group_id, group_type = nil, group.is_a?(Symbol) ? group.to_s : group
|
33
|
+
end
|
34
|
+
|
35
|
+
[group_id, group_type]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# The definition of the preference as defined in the owner's model
|
40
|
+
def definition
|
41
|
+
# Optimize number of queries to the database by only looking up the actual
|
42
|
+
# owner record for STI cases when the definition can't be found in the
|
43
|
+
# stored owner type class
|
44
|
+
owner_type && (find_definition(owner_type.constantize) || find_definition(owner.class))
|
45
|
+
end
|
46
|
+
|
47
|
+
# Typecasts the value depending on the preference definition's declared type
|
48
|
+
def value
|
49
|
+
value = read_attribute(:value)
|
50
|
+
value = definition.type_cast(value) if definition
|
51
|
+
value
|
52
|
+
end
|
53
|
+
|
54
|
+
# Only searches for the group record if the group id is specified
|
55
|
+
def group_with_optional_lookup
|
56
|
+
group_id ? group_without_optional_lookup : group_type
|
57
|
+
end
|
58
|
+
alias_method_chain :group, :optional_lookup
|
59
|
+
|
60
|
+
private
|
61
|
+
# Finds the definition for this preference in the given owner class.
|
62
|
+
def find_definition(owner_class)
|
63
|
+
owner_class.respond_to?(:preference_definitions) && owner_class.preference_definitions[name]
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreatePreferences < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :preferences do |t|
|
4
|
+
t.string :name, :null => false
|
5
|
+
t.references :owner, :polymorphic => true, :null => false
|
6
|
+
t.references :group, :polymorphic => true
|
7
|
+
t.string :value
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
add_index :preferences, [:owner_id, :owner_type, :name, :group_id, :group_type], :unique => true, :name => 'index_preferences_on_owner_and_name_and_preference'
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :preferences
|
15
|
+
end
|
16
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'preferences'
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Preferences
|
2
|
+
# Represents the definition of a preference for a particular model
|
3
|
+
class PreferenceDefinition
|
4
|
+
# The data type for the content stored in this preference type
|
5
|
+
attr_reader :type
|
6
|
+
|
7
|
+
def initialize(name, *args) #:nodoc:
|
8
|
+
options = args.extract_options!
|
9
|
+
options.assert_valid_keys(:default, :group_defaults)
|
10
|
+
|
11
|
+
@type = args.first ? args.first.to_sym : :boolean
|
12
|
+
|
13
|
+
# Create a column that will be responsible for typecasting
|
14
|
+
@column = ActiveRecord::ConnectionAdapters::Column.new(name.to_s, options[:default], @type == :any ? nil : @type.to_s)
|
15
|
+
|
16
|
+
@group_defaults = (options[:group_defaults] || {}).inject({}) do |defaults, (group, default)|
|
17
|
+
defaults[group.is_a?(Symbol) ? group.to_s : group] = type_cast(default)
|
18
|
+
defaults
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# The name of the preference
|
23
|
+
def name
|
24
|
+
@column.name
|
25
|
+
end
|
26
|
+
|
27
|
+
# The default value to use for the preference in case none have been
|
28
|
+
# previously defined
|
29
|
+
def default_value(group = nil)
|
30
|
+
@group_defaults.include?(group) ? @group_defaults[group] : @column.default
|
31
|
+
end
|
32
|
+
|
33
|
+
# Determines whether column backing this preference stores numberic values
|
34
|
+
def number?
|
35
|
+
@column.number?
|
36
|
+
end
|
37
|
+
|
38
|
+
# Typecasts the value based on the type of preference that was defined.
|
39
|
+
# This uses ActiveRecord's typecast functionality so the same rules for
|
40
|
+
# typecasting a model's columns apply here.
|
41
|
+
def type_cast(value)
|
42
|
+
@type == :any ? value : @column.type_cast(value)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Typecasts the value to true/false depending on the type of preference
|
46
|
+
def query(value)
|
47
|
+
if !(value = type_cast(value))
|
48
|
+
false
|
49
|
+
elsif number?
|
50
|
+
!value.zero?
|
51
|
+
else
|
52
|
+
!value.blank?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|