super_sti 0.2.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.
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/README +79 -0
- data/Rakefile +2 -0
- data/lib/super_sti/hook.rb +51 -0
- data/lib/super_sti/railtie.rb +12 -0
- data/lib/super_sti/version.rb +3 -0
- data/lib/super_sti.rb +3 -0
- data/spec/spec_helper.rb +50 -0
- data/spec/super_sti.rb +53 -0
- data/spec/test_classes.rb +31 -0
- data/super_sti.gemspec +24 -0
- metadata +90 -0
data/.rspec
ADDED
data/Gemfile
ADDED
data/README
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
Adds an add_extra_data method to ActiveRecord that invisibly includes an extra data table. Use with STI to keep your database clean. It removes the need to have lots of nullable columns.
|
2
|
+
|
3
|
+
Usage
|
4
|
+
---------
|
5
|
+
Use in Rails 3 app. Add to bundler:
|
6
|
+
gem "has_extra_data"
|
7
|
+
|
8
|
+
Tests
|
9
|
+
---------
|
10
|
+
Uses rspec for testing.
|
11
|
+
Run tests with rspec spec/*
|
12
|
+
|
13
|
+
Todo
|
14
|
+
---------
|
15
|
+
* Automatically load extra data class with main class.
|
16
|
+
* Automatically load associations in main class.
|
17
|
+
* Automatically pass attributes through to main class.
|
18
|
+
|
19
|
+
Example
|
20
|
+
---------
|
21
|
+
|
22
|
+
Usage:
|
23
|
+
|
24
|
+
Account.each do |account|
|
25
|
+
puts account.balance
|
26
|
+
end
|
27
|
+
|
28
|
+
BankAccount.each do |bank_account|
|
29
|
+
puts bank_account.balance
|
30
|
+
puts bank_account.bank.name
|
31
|
+
end
|
32
|
+
|
33
|
+
Classes:
|
34
|
+
class Account < ActiveRecord::Base
|
35
|
+
before_create :set_initial_balance
|
36
|
+
|
37
|
+
private
|
38
|
+
def set_initial_balance
|
39
|
+
self.balance = 0
|
40
|
+
true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class BankAccount < Account
|
45
|
+
has_extra_data do
|
46
|
+
belongs_to :bank
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class CreditCard < Account
|
51
|
+
has_extra_data
|
52
|
+
end
|
53
|
+
|
54
|
+
class Bank < ActiveRecord::Base
|
55
|
+
has_one :bank_account
|
56
|
+
end
|
57
|
+
|
58
|
+
Database Schema:
|
59
|
+
|
60
|
+
create_table :accounts do |t|
|
61
|
+
t.float :balance
|
62
|
+
end
|
63
|
+
|
64
|
+
create_table :bank_account_data do |t|
|
65
|
+
t.integer :bank_account_id, :null => false
|
66
|
+
t.integer :bank_id, :null => false
|
67
|
+
t.string :account_number, :null => false
|
68
|
+
t.string :sort_code, :null => false
|
69
|
+
end
|
70
|
+
|
71
|
+
create_table :credit_card_data do |t|
|
72
|
+
t.integer :credit_card_id, :null => false
|
73
|
+
t.string :credit_card_number, :null => false
|
74
|
+
t.date :expiry_date, :null => false
|
75
|
+
end
|
76
|
+
|
77
|
+
create_table :banks do |t|
|
78
|
+
t.string :name, :null => false
|
79
|
+
end
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module SuperSTI
|
2
|
+
module Hook
|
3
|
+
|
4
|
+
######
|
5
|
+
# has_extra_data(options = {})
|
6
|
+
#
|
7
|
+
# In it's most raw form, this method creates an associated Data class,
|
8
|
+
# which seamlessly adds attributes and methods to the main class
|
9
|
+
#
|
10
|
+
# If passed a block, extra attributes can be set on the data table,
|
11
|
+
# methods (e.g. has_many) can be called, and other methods can be defined.
|
12
|
+
#
|
13
|
+
# Options:
|
14
|
+
# table_name: The table name of the class
|
15
|
+
#####
|
16
|
+
def has_extra_data(options = {}, &block)
|
17
|
+
|
18
|
+
table_name = options[:table_name] || "#{self.name.underscore.gsub("/", "_")}_data"
|
19
|
+
klass = Class.new(ActiveRecord::Base) do
|
20
|
+
set_table_name(table_name)
|
21
|
+
end
|
22
|
+
klass.class_eval &block if block_given?
|
23
|
+
self.const_set "Data", klass
|
24
|
+
|
25
|
+
# Add a reference to a data object that gets created when this is created
|
26
|
+
has_one :data, :class_name => "#{self.name}::Data", :foreign_key => options[:foreign_key]
|
27
|
+
before_create :get_data
|
28
|
+
|
29
|
+
# A helper method which gets the existing data or builds a new object
|
30
|
+
define_method :get_data do
|
31
|
+
data || build_data
|
32
|
+
end
|
33
|
+
|
34
|
+
# Override respond_to? to check both this object and its data object.
|
35
|
+
define_method "respond_to?" do |sym, include_private = false|
|
36
|
+
super(sym, include_private) || get_data.respond_to?(sym, include_private)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Override method_missing to check both this object and it's data object for any methods or magic functionality.
|
40
|
+
# Firstly, try the original method_missing because there may well be
|
41
|
+
# some magic piping that will return a result and then try the data object.
|
42
|
+
define_method :method_missing do |sym, *args|
|
43
|
+
begin
|
44
|
+
super(sym, args)
|
45
|
+
rescue
|
46
|
+
get_data.send(sym, *args)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/super_sti.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
ENV["RAILS_ENV"] ||= 'test'
|
2
|
+
|
3
|
+
require 'rails'
|
4
|
+
require 'rspec-rails'
|
5
|
+
require 'active_record'
|
6
|
+
|
7
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
8
|
+
|
9
|
+
# Thie first line isn't working so I have added the second...
|
10
|
+
require File.dirname(__FILE__) + '/../lib/super_sti'
|
11
|
+
ActiveRecord::Base.send(:extend, SuperSTI::Hook)
|
12
|
+
|
13
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
14
|
+
|
15
|
+
# AR keeps printing annoying schema statements
|
16
|
+
$stdout = StringIO.new
|
17
|
+
|
18
|
+
ActiveRecord::Base.logger
|
19
|
+
ActiveRecord::Schema.define(:version => 1) do
|
20
|
+
create_table :accounts do |t|
|
21
|
+
t.float :balance
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table :bank_account_data do |t|
|
25
|
+
t.integer :bank_account_id, :null => false
|
26
|
+
t.integer :bank_id, :null => false
|
27
|
+
t.string :account_number, :null => false
|
28
|
+
t.string :sort_code, :null => false
|
29
|
+
end
|
30
|
+
|
31
|
+
create_table :credit_card_data do |t|
|
32
|
+
t.integer :credit_card_id, :null => false
|
33
|
+
t.string :credit_card_number, :null => false
|
34
|
+
t.date :expiry_date, :null => false
|
35
|
+
end
|
36
|
+
|
37
|
+
create_table :banks do |t|
|
38
|
+
t.string :name, :null => false
|
39
|
+
end
|
40
|
+
|
41
|
+
create_table :unusual_table_name do |t|
|
42
|
+
t.integer :unusual_table_name_id, :null => false
|
43
|
+
end
|
44
|
+
|
45
|
+
create_table :unusual_foreign_key_data do |t|
|
46
|
+
t.integer :unusual_foreign_key, :null => false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
require 'test_classes'
|
data/spec/super_sti.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Super STI models with has_extra_data models" do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@bank = Bank.create!(:name => "My Bank")
|
7
|
+
@bank_account = BankAccount.new
|
8
|
+
@valid_bank_account_attributes = {:account_number => "12345678", :sort_code => "12 34 56", :bank => @bank}
|
9
|
+
end
|
10
|
+
|
11
|
+
it "have the data method" do
|
12
|
+
@bank_account.should respond_to(:data)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can have variables set" do
|
16
|
+
@bank_account.account_number = "12345678"
|
17
|
+
@bank_account.sort_code = "12 34 56"
|
18
|
+
@bank_account.bank = @bank
|
19
|
+
@bank_account.save!
|
20
|
+
@bank_account.data.id.should_not == 0
|
21
|
+
end
|
22
|
+
|
23
|
+
it "creates data with the test class" do
|
24
|
+
@bank_account.attributes = @valid_bank_account_attributes
|
25
|
+
@bank_account.save!
|
26
|
+
@bank_account.data.id.should_not == 0
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can read attributes" do
|
30
|
+
@bank_account.attributes = @valid_bank_account_attributes
|
31
|
+
@bank_account.save!
|
32
|
+
@bank_account = BankAccount.find(@bank_account.id)
|
33
|
+
@bank_account.account_number.should == "12345678"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "can read associations" do
|
37
|
+
@bank_account.attributes = @valid_bank_account_attributes
|
38
|
+
@bank_account.save!
|
39
|
+
@bank_account = BankAccount.find(@bank_account.id)
|
40
|
+
@bank_account.bank.should == @bank
|
41
|
+
end
|
42
|
+
|
43
|
+
it "can have a specifc foreign_key" do
|
44
|
+
obj = UnusualForeignKey.create!
|
45
|
+
obj.data.should_not be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
it "can have any table name" do
|
49
|
+
obj = UnusualTableName.create!
|
50
|
+
obj.data.should_not be_nil
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Account < ActiveRecord::Base
|
2
|
+
before_create :set_initial_balance
|
3
|
+
|
4
|
+
private
|
5
|
+
def set_initial_balance
|
6
|
+
self.balance = 0
|
7
|
+
true
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class BankAccount < Account
|
12
|
+
has_extra_data do
|
13
|
+
belongs_to :bank
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class CreditCard < Account
|
18
|
+
has_extra_data
|
19
|
+
end
|
20
|
+
|
21
|
+
class UnusualForeignKey < Account
|
22
|
+
has_extra_data :foreign_key => "unusual_foreign_key"
|
23
|
+
end
|
24
|
+
|
25
|
+
class UnusualTableName < Account
|
26
|
+
has_extra_data :table_name => "unusual_table_name"
|
27
|
+
end
|
28
|
+
|
29
|
+
class Bank < ActiveRecord::Base
|
30
|
+
has_one :bank_account
|
31
|
+
end
|
data/super_sti.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "super_sti/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "super_sti"
|
7
|
+
s.version = SuperSTI::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Jeremy Walker"]
|
10
|
+
s.email = ["jez.walker@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Ruby Rails - Add has_extra_data to SDI models with clean database tables.}
|
13
|
+
s.description = %q{Adds an add_extra_data method to ActiveRecord that invisibly includes an extra data table. Means you can use STI but keep your database clean.}
|
14
|
+
|
15
|
+
s.add_dependency "rails"
|
16
|
+
s.add_development_dependency "rspec-rails"
|
17
|
+
|
18
|
+
s.rubyforge_project = "has_extra_data"
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: super_sti
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.2.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jeremy Walker
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-05-18 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rails
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rspec-rails
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id002
|
37
|
+
description: Adds an add_extra_data method to ActiveRecord that invisibly includes an extra data table. Means you can use STI but keep your database clean.
|
38
|
+
email:
|
39
|
+
- jez.walker@gmail.com
|
40
|
+
executables: []
|
41
|
+
|
42
|
+
extensions: []
|
43
|
+
|
44
|
+
extra_rdoc_files: []
|
45
|
+
|
46
|
+
files:
|
47
|
+
- .gitignore
|
48
|
+
- .rspec
|
49
|
+
- Gemfile
|
50
|
+
- README
|
51
|
+
- Rakefile
|
52
|
+
- lib/super_sti.rb
|
53
|
+
- lib/super_sti/hook.rb
|
54
|
+
- lib/super_sti/railtie.rb
|
55
|
+
- lib/super_sti/version.rb
|
56
|
+
- spec/spec_helper.rb
|
57
|
+
- spec/super_sti.rb
|
58
|
+
- spec/test_classes.rb
|
59
|
+
- super_sti.gemspec
|
60
|
+
homepage: ""
|
61
|
+
licenses: []
|
62
|
+
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
requirements: []
|
81
|
+
|
82
|
+
rubyforge_project: has_extra_data
|
83
|
+
rubygems_version: 1.7.2
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: Ruby Rails - Add has_extra_data to SDI models with clean database tables.
|
87
|
+
test_files:
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
- spec/super_sti.rb
|
90
|
+
- spec/test_classes.rb
|