has_magic_fields 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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +1 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +176 -0
- data/Rakefile +7 -0
- data/has_magic_fields.gemspec +25 -0
- data/lib/app/models/magic_attribute.rb +9 -0
- data/lib/app/models/magic_attribute_relationship.rb +4 -0
- data/lib/app/models/magic_field.rb +35 -0
- data/lib/app/models/magic_field_relationship.rb +15 -0
- data/lib/generators/has_magic_fields/install/USAGE +8 -0
- data/lib/generators/has_magic_fields/install/install_generator.rb +24 -0
- data/lib/generators/has_magic_fields/install/templates/migration.rb +47 -0
- data/lib/has_magic_fields.rb +5 -0
- data/lib/has_magic_fields/extend.rb +121 -0
- data/lib/has_magic_fields/version.rb +3 -0
- data/rails/init.rb +1 -0
- data/spec/has_magic_fields/magic_fileds_spec.rb +142 -0
- data/spec/spec_helper.rb +98 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: eb713aa099438a9901feff56b085d42bdad641b2
|
4
|
+
data.tar.gz: 847b8af1426f1ece5b7977287daf2285b8df9029
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7c10c59001c407cc3919d991917daa638e4c7f26cf5b9729564b00df3988c0b2be400be2e6555a1e5c9920f26fea614b96bcb8dbc9fe25a6ab758006852cb3aa
|
7
|
+
data.tar.gz: 57d5d0600678bba874dc9d45a7a49529e94383a089f4ef7499b2d852e340d88c090bd2005515cf86adf53f1f68ba975a830bb35b7fbe44c8933afc20c7b10ff3
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color --format documentation
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 ikeqiao
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
# HasMagicFields
|
2
|
+
[](http://badge.fury.io/rb/has_magic_fields)
|
3
|
+
|
4
|
+
Allows the addition of custom "magic" fields and attributes on a per-model
|
5
|
+
or per-parent-model basis. This is useful for situations where custom fields are
|
6
|
+
required for a specific model or for multi-user, multi-account environments where
|
7
|
+
accounts can customize attributes for subordinate models.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'has_magic_fields'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
|
20
|
+
Create the migrations for MagicFileds and migrate:
|
21
|
+
|
22
|
+
rails g has_magic_fields:install
|
23
|
+
rake db:migrate
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
### Model
|
30
|
+
|
31
|
+
Sprinkle a little magic into an existing model:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
class Person < ActiveRecord::Base
|
35
|
+
include HasMagicFields::Extend
|
36
|
+
has_magic_fields
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
Add magic fields to your model:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
@charlie = Person.create(:email => "charlie@example.com")
|
44
|
+
@charlie.create_magic_fields(:name => "first_name")
|
45
|
+
```
|
46
|
+
|
47
|
+
Supply additional options if you have more specific requirements for your fields:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
@charlie.create_magic_fields(:name => "last_name", :is_required => true)
|
51
|
+
@charlie.create_magic_fields(:name => "birthday", :datatype => :date)
|
52
|
+
@charlie.create_magic_fields(:name => "salary", :default => "40000", :pretty_name => "Yearly Salary")
|
53
|
+
```
|
54
|
+
|
55
|
+
The `:datatype` option supports: `:check_box_boolean`, `:date`, `:datetime`, `:integer`
|
56
|
+
|
57
|
+
Use your new fields just like you would with any other ActiveRecord attribute:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
@charlie.first_name = "Charlie"
|
61
|
+
@charlie.last_name = "Magic!"
|
62
|
+
@charlie.birthday = Date.today
|
63
|
+
@charlie.save
|
64
|
+
```
|
65
|
+
|
66
|
+
Find @charlie and inspect him:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
@charlie = User.find(@charlie.id)
|
70
|
+
@charlie.first_name #=> "Charlie"
|
71
|
+
@charlie.last_name #=> "Magic!"
|
72
|
+
@charlie.birthday #=> #<Date: 4908497/2,0,2299161>
|
73
|
+
@charlie.salary #=> "40000", this is from :salary having a :default
|
74
|
+
```
|
75
|
+
|
76
|
+
## Inherited Model
|
77
|
+
|
78
|
+
A child can inherit magic fields from a parent. To do this, declare the parent
|
79
|
+
as having magic fields:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
class Account < ActiveRecord::Base
|
83
|
+
include HasMagicFields::Extend
|
84
|
+
has_many :users
|
85
|
+
has_magic_fields
|
86
|
+
end
|
87
|
+
@account = Account.create(:name => "BobCorp",:type_scoped => "User")
|
88
|
+
```
|
89
|
+
|
90
|
+
And declare the child as having magic fields :through the parent.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
class User < ActiveRecord::Base
|
94
|
+
include HasMagicFields::Extend
|
95
|
+
belongs_to :account
|
96
|
+
has_magic_fields :through => :account
|
97
|
+
end
|
98
|
+
@alice = User.create(:name => "alice", :account => @account)
|
99
|
+
```
|
100
|
+
|
101
|
+
To see all the magic fields available for a type_scoped(User) child from its parent:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
@alice.magic_fields #=> [#<MagicColumn>,...]
|
105
|
+
```
|
106
|
+
|
107
|
+
To add magic fields, go through the parent or child:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
@alice.create_magic_fields(...)
|
111
|
+
@account.create_magic_fields(…,:type_scoped => "User")
|
112
|
+
```
|
113
|
+
|
114
|
+
All User children for a given parent will have access to the same magic fields:
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
@alice.create_magic_fields(:name => "salary")
|
118
|
+
@alice.salary = "40000"
|
119
|
+
|
120
|
+
@bob = User.create(:name => "bob", :account => @account)
|
121
|
+
# Magic! No need to add the column again!
|
122
|
+
@bob.salary = "50000"
|
123
|
+
```
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
###Different Model Inherited from The Samle Model
|
128
|
+
the other modle Inherited from Account
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
class Product < ActiveRecord::Base
|
132
|
+
include HasMagicFields::Extend
|
133
|
+
belongs_to :account
|
134
|
+
has_magic_fields :through => :account
|
135
|
+
end
|
136
|
+
|
137
|
+
@product = Product.create(:name => "car", :account => @account)
|
138
|
+
```
|
139
|
+
@product haven't salary magic field, @product.salary should raise NoMethodError
|
140
|
+
|
141
|
+
parent @account also haven't salary magic field
|
142
|
+
|
143
|
+
## get all magic fields
|
144
|
+
```ruby
|
145
|
+
@account.magic_fields #get all meagic_fields both self and children
|
146
|
+
@account.magic_fields_with_scoped #get all meagic_fields self
|
147
|
+
@account.magic_fields_with_scoped("User") #get all meagic_fields User model
|
148
|
+
```
|
149
|
+
|
150
|
+
##To Do
|
151
|
+
|
152
|
+
Here's a short list of things that need to be done to polish up this gem:
|
153
|
+
|
154
|
+
* more data_type sppuort
|
155
|
+
* Benchmark and optimize
|
156
|
+
|
157
|
+
Maintainers
|
158
|
+
===========
|
159
|
+
|
160
|
+
* Davy Zhou([ikeqiao](http://github.com/ikeqiao))
|
161
|
+
|
162
|
+
|
163
|
+
## Contributing
|
164
|
+
|
165
|
+
1. Fork it
|
166
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
167
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
168
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
169
|
+
5. Create new Pull Request
|
170
|
+
|
171
|
+
|
172
|
+
Credits
|
173
|
+
=======
|
174
|
+
|
175
|
+
* Thank you to Brandon Keene for his original work making this plugin.
|
176
|
+
* Thank you to latortuga for his original work making this plugin. [has_magic_fields](https://github.com/latortuga/has_magic_columns.git)
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'has_magic_fields/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "has_magic_fields"
|
8
|
+
s.version = HasMagicFields::VERSION
|
9
|
+
s.authors = ["ikeqiao"]
|
10
|
+
s.email = ["zhzsi@126.com"]
|
11
|
+
s.description = %q{Custom fields forActiveRecord models, suppport Rails 4!}
|
12
|
+
s.summary = %q{Allow addition of custom 'magic' fields to ActiveRecord models.}
|
13
|
+
s.homepage = "https://github.com/ikeqiao/has_magic_fields"
|
14
|
+
s.license = "MIT"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split($/)
|
17
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
s.test_files = s.files.grep(%r{^(test|s|features)/})
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
s.add_development_dependency "rake"
|
23
|
+
s.add_dependency("rails", [">= 4.0.0"])
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class MagicField < ActiveRecord::Base
|
2
|
+
has_many :magic_field_relationships, :dependent => :destroy
|
3
|
+
has_many :owners, :through => :magic_field_relationships, :as => :owner
|
4
|
+
has_many :magic_attributes, :dependent => :destroy
|
5
|
+
|
6
|
+
validates_presence_of :name, :datatype
|
7
|
+
validates_format_of :name, :with => /\A[a-z][a-z0-9_]+\z/
|
8
|
+
|
9
|
+
def type_cast(value)
|
10
|
+
begin
|
11
|
+
case datatype.to_sym
|
12
|
+
when :check_box_boolean
|
13
|
+
(value.to_int == 1) ? true : false
|
14
|
+
when :date
|
15
|
+
Date.parse(value)
|
16
|
+
when :datetime
|
17
|
+
Time.parse(value)
|
18
|
+
when :integer
|
19
|
+
value.to_int
|
20
|
+
else
|
21
|
+
value
|
22
|
+
end
|
23
|
+
rescue
|
24
|
+
value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Display a nicer (possibly user-defined) name for the column or use a fancified default.
|
29
|
+
def pretty_name
|
30
|
+
super || name.humanize
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class MagicFieldRelationship < ActiveRecord::Base
|
2
|
+
belongs_to :magic_field
|
3
|
+
belongs_to :owner, :polymorphic => true
|
4
|
+
#belongs_to :extended_model, :polymorphic => true
|
5
|
+
validates_uniqueness_of :name, scope: [:owner_id, :owner_type, :type_scoped]
|
6
|
+
validates_presence_of :name, :type_scoped
|
7
|
+
|
8
|
+
before_validation :sync_name
|
9
|
+
|
10
|
+
def sync_name
|
11
|
+
self.name = magic_field.name
|
12
|
+
self.type_scoped = magic_field.type_scoped.blank? ? self.owner_type : magic_field.type_scoped
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module HasMagicFields
|
4
|
+
class InstallGenerator < Rails::Generators::Base
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
|
7
|
+
source_root File.expand_path('../templates',__FILE__)
|
8
|
+
|
9
|
+
desc "Add has_magic_fields migration."
|
10
|
+
|
11
|
+
def self.next_migration_number(path)
|
12
|
+
unless @prev_migration_nr
|
13
|
+
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
14
|
+
else
|
15
|
+
@prev_migration_nr += 1
|
16
|
+
end
|
17
|
+
@prev_migration_nr.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_migration
|
21
|
+
migration_template "migration.rb", "db/migrate/add_has_magic_fields_tables.rb"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class AddHasMagicFieldsTables < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :magic_fields do |t|
|
4
|
+
t.column :name, :string
|
5
|
+
t.column :pretty_name, :string
|
6
|
+
t.column :datatype, :string, :default => "string"
|
7
|
+
t.column :default, :string
|
8
|
+
t.column :is_required, :boolean, :default => false
|
9
|
+
t.column :include_blank, :boolean, :default => false
|
10
|
+
t.column :allow_other, :boolean, :default => true
|
11
|
+
t.column :type_scoped, :string
|
12
|
+
t.column :created_at, :datetime
|
13
|
+
t.column :updated_at, :datetime
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table :magic_attributes do |t|
|
17
|
+
t.column :magic_field_id, :integer
|
18
|
+
t.column :value, :string
|
19
|
+
t.column :created_at, :datetime
|
20
|
+
t.column :updated_at, :datetime
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
create_table :magic_field_relationships do |t|
|
25
|
+
t.column :magic_field_id, :integer
|
26
|
+
t.column :owner_id, :integer
|
27
|
+
t.column :owner_type, :string
|
28
|
+
t.column :name, :string
|
29
|
+
t.column :type_scoped, :string
|
30
|
+
t.column :created_at, :datetime
|
31
|
+
t.column :updated_at, :datetime
|
32
|
+
end
|
33
|
+
|
34
|
+
create_table :magic_attribute_relationships do |t|
|
35
|
+
t.column :magic_attribute_id, :integer
|
36
|
+
t.column :owner_id, :integer
|
37
|
+
t.column :owner_type, :string
|
38
|
+
t.column :created_at, :datetime
|
39
|
+
t.column :updated_at, :datetime
|
40
|
+
end
|
41
|
+
|
42
|
+
add_index :magic_attribute_relationships, [:magic_attribute_id, :owner_id, :owner_type], name:"magic_attribute_id_owner", :unique => true
|
43
|
+
add_index :magic_field_relationships, [:magic_field_id, :owner_id, :owner_type], name:"magic_field_id_owner", :unique => true
|
44
|
+
add_index :magic_field_relationships, [:name, :type_scoped, :owner_id, :owner_type], name:"magic_field_name_owner", :unique => true
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
module HasMagicFields
|
5
|
+
module Extend extend ActiveSupport::Concern
|
6
|
+
include ActiveModel::Validations
|
7
|
+
module ClassMethods
|
8
|
+
def has_magic_fields(options = {})
|
9
|
+
# Associations
|
10
|
+
has_many :magic_attribute_relationships, :as => :owner, :dependent => :destroy
|
11
|
+
has_many :magic_attributes, :through => :magic_attribute_relationships, :dependent => :destroy
|
12
|
+
|
13
|
+
# Inheritence
|
14
|
+
cattr_accessor :inherited_from
|
15
|
+
|
16
|
+
|
17
|
+
# if options[:through] is supplied, treat as an inherited relationship
|
18
|
+
if self.inherited_from = options[:through]
|
19
|
+
class_eval do
|
20
|
+
def inherited_magic_fields
|
21
|
+
raise "Cannot inherit MagicFields from a non-existant association: #{@inherited_from}" unless self.class.method_defined?(inherited_from)# and self.send(inherited_from)
|
22
|
+
self.send(inherited_from).magic_fields
|
23
|
+
end
|
24
|
+
end
|
25
|
+
alias_method :magic_fields, :inherited_magic_fields unless method_defined? :magic_fields
|
26
|
+
|
27
|
+
# otherwise the calling model has the relationships
|
28
|
+
else
|
29
|
+
has_many :magic_field_relationships, :as => :owner, :dependent => :destroy
|
30
|
+
has_many :magic_fields, :through => :magic_field_relationships, :dependent => :destroy
|
31
|
+
# alias_method_chain :magic_fields, :scoped
|
32
|
+
end
|
33
|
+
alias_method :magic_fields_without_scoped, :magic_fields
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
included do
|
39
|
+
|
40
|
+
def create_magic_filed(options = {})
|
41
|
+
type_scoped = options[:type_scoped].blank? ? self.class.name : options[:type_scoped].classify
|
42
|
+
self.magic_fields.create options.merge(type_scoped: type_scoped )
|
43
|
+
end
|
44
|
+
|
45
|
+
def magic_fields_with_scoped(type_scoped = nil)
|
46
|
+
type_scoped = type_scoped.blank? ? self.class.name : type_scoped.classify
|
47
|
+
magic_fields_without_scoped.where(type_scoped: type_scoped)
|
48
|
+
end
|
49
|
+
|
50
|
+
def method_missing(method_id, *args)
|
51
|
+
super(method_id, *args)
|
52
|
+
rescue NoMethodError
|
53
|
+
method_name = method_id.to_s
|
54
|
+
super(method_id, *args) unless magic_field_names.include?(method_name) or (md = /[\?|\=]/.match(method_name) and magic_field_names.include?(md.pre_match))
|
55
|
+
|
56
|
+
if method_name =~ /=$/
|
57
|
+
var_name = method_name.gsub('=', '')
|
58
|
+
value = args.first
|
59
|
+
write_magic_attribute(var_name,value)
|
60
|
+
else
|
61
|
+
read_magic_attribute(method_name)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def magic_field_names(type_scoped = nil)
|
66
|
+
magic_fields_with_scoped(type_scoped).map(&:name)
|
67
|
+
end
|
68
|
+
|
69
|
+
def valid?(context = nil)
|
70
|
+
output = super(context)
|
71
|
+
magic_fields_with_scoped.each do |field|
|
72
|
+
if field.is_required?
|
73
|
+
validates_presence_of(field.name)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
errors.empty? && output
|
77
|
+
end
|
78
|
+
|
79
|
+
# Load the MagicAttribute(s) associated with attr_name and cast them to proper type.
|
80
|
+
def read_magic_attribute(field_name)
|
81
|
+
field = find_magic_field_by_name(field_name)
|
82
|
+
attribute = find_magic_attribute_by_field(field)
|
83
|
+
value = (attr = attribute.first) ? attr.to_s : field.default
|
84
|
+
value.nil? ? nil : field.type_cast(value)
|
85
|
+
end
|
86
|
+
|
87
|
+
def write_magic_attribute(field_name, value)
|
88
|
+
field = find_magic_field_by_name(field_name)
|
89
|
+
attribute = find_magic_attribute_by_field(field)
|
90
|
+
(attr = attribute.first) ? update_magic_attribute(attr, value) : create_magic_attribute(field, value)
|
91
|
+
end
|
92
|
+
|
93
|
+
def find_magic_attribute_by_field(field)
|
94
|
+
magic_attributes.to_a.find_all {|attr| attr.magic_field_id == field.id}
|
95
|
+
end
|
96
|
+
|
97
|
+
def find_magic_field_by_name(attr_name)
|
98
|
+
magic_fields_with_scoped.to_a.find {|column| column.name == attr_name}
|
99
|
+
end
|
100
|
+
|
101
|
+
def create_magic_attribute(magic_field, value)
|
102
|
+
magic_attributes << MagicAttribute.create(:magic_field => magic_field, :value => value)
|
103
|
+
end
|
104
|
+
|
105
|
+
def update_magic_attribute(magic_attribute, value)
|
106
|
+
magic_attribute.update_attributes(:value => value)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
%w{ models }.each do |dir|
|
112
|
+
path = File.join(File.dirname(__FILE__), '../app', dir)
|
113
|
+
$LOAD_PATH << path
|
114
|
+
ActiveSupport::Dependencies.autoload_paths << path
|
115
|
+
ActiveSupport::Dependencies.autoload_once_paths.delete(path)
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'has_magic_fields'
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe HasMagicFields do
|
5
|
+
|
6
|
+
context "on a single model" do
|
7
|
+
before(:each) do
|
8
|
+
@charlie = Person.create(name: "charlie")
|
9
|
+
end
|
10
|
+
|
11
|
+
it "initializes magic fields correctly" do
|
12
|
+
expect(@charlie).not_to be(nil)
|
13
|
+
expect(@charlie.class).to be(Person)
|
14
|
+
expect(@charlie.magic_fields).not_to be(nil)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "allows adding a magic field" do
|
18
|
+
@charlie.create_magic_filed(:name => 'salary')
|
19
|
+
expect(@charlie.magic_fields.length).to eq(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "validates_uniqueness_of name in a object" do
|
23
|
+
@charlie.create_magic_filed(:name => 'salary')
|
24
|
+
before_fields_count = MagicField.count
|
25
|
+
expect(@charlie.magic_fields.length).to eq(1)
|
26
|
+
expect(lambda{@charlie.create_magic_filed(:name => 'salary')}).to raise_error
|
27
|
+
expect(@charlie.magic_fields.length).to eq(1)
|
28
|
+
after_fields_count = MagicField.count
|
29
|
+
expect(before_fields_count).to eq(after_fields_count)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "allows setting and saving of magic attributes" do
|
33
|
+
@charlie.create_magic_filed(:name => 'salary')
|
34
|
+
@charlie.salary = 50000
|
35
|
+
@charlie.save
|
36
|
+
@charlie = Person.find(@charlie.id)
|
37
|
+
expect(@charlie.salary).not_to be(nil)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "forces required if is_required is true" do
|
41
|
+
@charlie.create_magic_filed(:name => "last_name", :is_required => true)
|
42
|
+
expect(@charlie.save).to be(false)
|
43
|
+
@charlie.last_name = "zongsi"
|
44
|
+
expect(@charlie.save).to be(true)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "allows datatype to be :date" do
|
48
|
+
@charlie.create_magic_filed(:name => "birthday", :datatype => :date)
|
49
|
+
@charlie.birthday = Date.today
|
50
|
+
expect(@charlie.save).to be(true)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "allows datatype to be :datetime" do
|
54
|
+
@charlie.create_magic_filed(:name => "signed_up_at", :datatype => :datetime)
|
55
|
+
@charlie.signed_up_at = DateTime.now
|
56
|
+
expect(@charlie.save).to be(true)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "allows datatype to be :integer" do
|
60
|
+
@charlie.create_magic_filed(:name => "age", :datatype => :integer)
|
61
|
+
@charlie.age = 5
|
62
|
+
expect(@charlie.save).to be(true)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "allows datatype to be :check_box_boolean" do
|
66
|
+
@charlie.create_magic_filed(:name => "retired", :datatype => :check_box_boolean)
|
67
|
+
@charlie.retired = false
|
68
|
+
expect(@charlie.save).to be(true)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "allows default to be set" do
|
72
|
+
@charlie.create_magic_filed(:name => "bonus", :default => "40000")
|
73
|
+
expect(@charlie.bonus).to eq("40000")
|
74
|
+
end
|
75
|
+
|
76
|
+
it "allows a pretty display name to be set" do
|
77
|
+
@charlie.create_magic_filed(:name => "zip", :pretty_name => "Zip Code")
|
78
|
+
expect(@charlie.magic_fields.last.pretty_name).to eq("Zip Code")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "in a parent-child relationship" do
|
83
|
+
before(:each) do
|
84
|
+
@account = Account.create(name:"important")
|
85
|
+
@alice = User.create(name:"alice", account: @account )
|
86
|
+
@product = Product.create(name:"TR", account: @account )
|
87
|
+
end
|
88
|
+
|
89
|
+
it "initializes magic fields correctly" do
|
90
|
+
expect(@alice).not_to be(nil)
|
91
|
+
expect(@alice.class).to be(User)
|
92
|
+
expect(@alice.magic_fields).not_to be(nil)
|
93
|
+
|
94
|
+
expect(@account).not_to be(nil)
|
95
|
+
expect(@account.class).to be(Account)
|
96
|
+
expect(@alice.magic_fields).not_to be(nil)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "allows adding a magic field from the child" do
|
100
|
+
@alice.create_magic_filed(:name => 'salary')
|
101
|
+
expect(@alice.magic_fields.length).to eq(1)
|
102
|
+
expect(lambda{@alice.salary}).not_to raise_error
|
103
|
+
expect(lambda{@account.salary}).to raise_error
|
104
|
+
end
|
105
|
+
|
106
|
+
it "allows adding a magic field from the parent" do
|
107
|
+
@account.create_magic_filed(:name => 'age',type_scoped: "User")
|
108
|
+
expect(lambda{@alice.age}).not_to raise_error
|
109
|
+
end
|
110
|
+
|
111
|
+
it "sets magic fields for all child models" do
|
112
|
+
@bob = User.create(name:"bob", account: @account )
|
113
|
+
@bob.create_magic_filed(:name => 'birthday')
|
114
|
+
expect(lambda{@alice.birthday}).not_to raise_error
|
115
|
+
@bob.birthday = "2014-07-29"
|
116
|
+
expect(@bob.save).to be(true)
|
117
|
+
expect(@alice.birthday).to be(nil)
|
118
|
+
@alice.birthday = "2013-07-29"
|
119
|
+
expect(@alice.save).to be(true)
|
120
|
+
expect(@alice.birthday).not_to eq(@bob.birthday)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "defferent model has defferent scope" do
|
124
|
+
@alice.create_magic_filed(:name => 'salary')
|
125
|
+
expect(lambda{@alice.salary}).not_to raise_error
|
126
|
+
expect(lambda{@product.salary}).to raise_error
|
127
|
+
end
|
128
|
+
|
129
|
+
it "validates_uniqueness_of name in all models object" do
|
130
|
+
@alice.create_magic_filed(:name => 'salary')
|
131
|
+
before_fields_count = MagicField.count
|
132
|
+
expect(@alice.magic_fields.length).to eq(1)
|
133
|
+
expect(lambda{@alice.create_magic_filed(:name => 'salary')}).to raise_error
|
134
|
+
expect(@alice.magic_fields.length).to eq(1)
|
135
|
+
expect(before_fields_count).to eq(MagicField.count)
|
136
|
+
@bob = User.create(name:"bob", account: @account )
|
137
|
+
expect(lambda{@bob.create_magic_filed(:name => 'salary')}).to raise_error
|
138
|
+
expect(lambda{@product.create_magic_filed(:name => 'salary')}).not_to raise_error
|
139
|
+
expect(lambda{@account.create_magic_filed(:name => 'salary')}).not_to raise_error
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
|
2
|
+
require 'debugger'
|
3
|
+
require 'database_cleaner'
|
4
|
+
require 'rubygems'
|
5
|
+
require "active_record"
|
6
|
+
require 'active_support'
|
7
|
+
require 'sqlite3'
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
10
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'rails'))
|
11
|
+
require "init"
|
12
|
+
|
13
|
+
require "rails/railtie"
|
14
|
+
|
15
|
+
module Rails
|
16
|
+
def self.env
|
17
|
+
@_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
24
|
+
# ActiveRecord::Base.configurations = true
|
25
|
+
# ActiveRecord::Base.logger = Logger.new(STDOUT)
|
26
|
+
|
27
|
+
ActiveRecord::Schema.verbose = false
|
28
|
+
|
29
|
+
ActiveRecord::Schema.define do
|
30
|
+
|
31
|
+
create_table "users", :force => true do |t|
|
32
|
+
t.column "name", :text
|
33
|
+
t.column "account_id", :integer
|
34
|
+
end
|
35
|
+
|
36
|
+
create_table "people", :force => true do |t|
|
37
|
+
t.column "name", :text
|
38
|
+
end
|
39
|
+
|
40
|
+
create_table "accounts", :force => true do |t|
|
41
|
+
t.column "name", :text
|
42
|
+
end
|
43
|
+
|
44
|
+
create_table "products", :force => true do |t|
|
45
|
+
t.column "name", :text
|
46
|
+
t.column "account_id", :integer
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
require_relative '../lib/generators/has_magic_fields/install/templates/migration'
|
51
|
+
AddHasMagicFieldsTables.new.change
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
RSpec.configure do |config|
|
57
|
+
|
58
|
+
config.before(:all) do
|
59
|
+
class Account < ActiveRecord::Base
|
60
|
+
include HasMagicFields::Extend
|
61
|
+
has_many :users
|
62
|
+
has_magic_fields
|
63
|
+
end
|
64
|
+
|
65
|
+
class Person < ActiveRecord::Base
|
66
|
+
include HasMagicFields::Extend
|
67
|
+
has_magic_fields
|
68
|
+
end
|
69
|
+
|
70
|
+
class User < ActiveRecord::Base
|
71
|
+
include HasMagicFields::Extend
|
72
|
+
belongs_to :account
|
73
|
+
has_magic_fields :through => :account
|
74
|
+
end
|
75
|
+
|
76
|
+
class Product < ActiveRecord::Base
|
77
|
+
include HasMagicFields::Extend
|
78
|
+
belongs_to :account
|
79
|
+
has_magic_fields :through => :account
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
config.after(:all) do
|
85
|
+
end
|
86
|
+
|
87
|
+
config.before(:suite) do
|
88
|
+
DatabaseCleaner.strategy = :transaction
|
89
|
+
DatabaseCleaner.clean_with(:truncation)
|
90
|
+
end
|
91
|
+
|
92
|
+
config.around(:each) do |example|
|
93
|
+
DatabaseCleaner.cleaning do
|
94
|
+
example.run
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: has_magic_fields
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ikeqiao
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-07-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 4.0.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 4.0.0
|
55
|
+
description: Custom fields forActiveRecord models, suppport Rails 4!
|
56
|
+
email:
|
57
|
+
- zhzsi@126.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- .rspec
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- has_magic_fields.gemspec
|
69
|
+
- lib/app/models/magic_attribute.rb
|
70
|
+
- lib/app/models/magic_attribute_relationship.rb
|
71
|
+
- lib/app/models/magic_field.rb
|
72
|
+
- lib/app/models/magic_field_relationship.rb
|
73
|
+
- lib/generators/has_magic_fields/install/USAGE
|
74
|
+
- lib/generators/has_magic_fields/install/install_generator.rb
|
75
|
+
- lib/generators/has_magic_fields/install/templates/migration.rb
|
76
|
+
- lib/has_magic_fields.rb
|
77
|
+
- lib/has_magic_fields/extend.rb
|
78
|
+
- lib/has_magic_fields/version.rb
|
79
|
+
- rails/init.rb
|
80
|
+
- spec/has_magic_fields/magic_fileds_spec.rb
|
81
|
+
- spec/spec_helper.rb
|
82
|
+
homepage: https://github.com/ikeqiao/has_magic_fields
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata: {}
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 2.0.3
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: Allow addition of custom 'magic' fields to ActiveRecord models.
|
106
|
+
test_files: []
|