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.
@@ -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
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ log
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format documentation
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "http://ruby.taobao.org"
2
+
3
+ gem 'rails', ' >= 4.0.0'
4
+
5
+ group :test do
6
+ gem 'rspec-rails', ' >= 3.0.0'
7
+ gem 'sqlite3'
8
+ gem 'database_cleaner'
9
+ end
@@ -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.
@@ -0,0 +1,176 @@
1
+ # HasMagicFields
2
+ [![Gem Version](https://badge.fury.io/rb/has_magic_fields.png)](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)
@@ -0,0 +1,7 @@
1
+ require 'rake'
2
+ require "rspec"
3
+ require File.expand_path('../spec/spec_helper', __FILE__)
4
+
5
+ task :default do
6
+ system 'bundle exec rspec spec'
7
+ end
@@ -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,9 @@
1
+ # Always work through the interface MagicAttribute.value
2
+ class MagicAttribute < ActiveRecord::Base
3
+ belongs_to :magic_field
4
+
5
+ def to_s
6
+ value
7
+ end
8
+
9
+ end
@@ -0,0 +1,4 @@
1
+ class MagicAttributeRelationship < ActiveRecord::Base
2
+ belongs_to :magic_attribute
3
+ belongs_to :owner, :polymorphic => true
4
+ 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,8 @@
1
+ Description:
2
+ Add a migration for has_magic_fields.
3
+
4
+ Example:
5
+ rails generate has_magic_fields:install
6
+
7
+ This will create:
8
+ db/migrate/XXX_add_has_magic_fields_tables.rb
@@ -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,5 @@
1
+ require "has_magic_fields/version"
2
+ require "has_magic_fields/extend"
3
+
4
+
5
+
@@ -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
+
@@ -0,0 +1,3 @@
1
+ module HasMagicFields
2
+ VERSION = "0.0.1"
3
+ end
@@ -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
@@ -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: []