schema_associations 0.1.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +25 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +25 -0
- data/README.rdoc +89 -0
- data/Rakefile +59 -0
- data/init.rb +1 -0
- data/lib/schema_associations/active_record/associations.rb +223 -0
- data/lib/schema_associations/railtie.rb +9 -0
- data/lib/schema_associations/version.rb +3 -0
- data/lib/schema_associations.rb +112 -0
- data/schema_associations.gemspec +32 -0
- data/schema_associations.gemspec.rails3.0 +35 -0
- data/schema_associations.gemspec.rails3.1 +36 -0
- data/spec/association_spec.rb +543 -0
- data/spec/connection.rb +10 -0
- data/spec/spec_helper.rb +29 -0
- metadata +163 -0
data/.gitignore
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
## MAC OS
|
2
|
+
.DS_Store
|
3
|
+
|
4
|
+
## TEXTMATE
|
5
|
+
*.tmproj
|
6
|
+
tmtags
|
7
|
+
|
8
|
+
## EMACS
|
9
|
+
*~
|
10
|
+
\#*
|
11
|
+
.\#*
|
12
|
+
|
13
|
+
## VIM
|
14
|
+
.*.sw?
|
15
|
+
|
16
|
+
## PROJECT::GENERAL
|
17
|
+
coverage
|
18
|
+
rdoc
|
19
|
+
pkg
|
20
|
+
|
21
|
+
## PROJECT::SPECIFIC
|
22
|
+
.rvmrc
|
23
|
+
*.log
|
24
|
+
*.sqlite3
|
25
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Copyright (c) 2006 RedHill Consulting, Pty. Ltd.
|
2
|
+
Copyright (c) 2009 Michal Lomnicki & Ronen Barzel
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
Except as contained in this notice, the name(s) of the above copyright
|
16
|
+
holders shall not be used in advertising or otherwise to promote the sale,
|
17
|
+
use or other dealings in this Software without prior written authorization.
|
18
|
+
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
20
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
21
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
22
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
23
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
24
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
25
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
= SchemaAssociations
|
2
|
+
|
3
|
+
== Overview
|
4
|
+
|
5
|
+
One of the great things about Rails (ActiveRecord, in particular) is that it
|
6
|
+
inspects the database and automatically defines accessors for all your
|
7
|
+
columns, keeping your model class definitions simple and DRY. That's great
|
8
|
+
for simple data columns, but where it falls down is when your table
|
9
|
+
contains references to other tables: then the "accessors" you need are the
|
10
|
+
+belongs_to+, +has_one+, +has_many+, and +has_and_belongs_to_many+
|
11
|
+
associations -- and you need to put them into your model class definitions by hand, which isn't so DRY.
|
12
|
+
|
13
|
+
Enter the SchemaAssociations gem. It extends ActiveRecord to automatically
|
14
|
+
define the appropriate associations based on foreign key constraints in the
|
15
|
+
database. SchemaAssociations builds on the
|
16
|
+
{+schema_plus+}[http://rubygems.org/gems/schema_plus] gem that
|
17
|
+
automatically defines foreign key constraints. So the common case is simple -- if you have this in your migration:
|
18
|
+
|
19
|
+
create_table :posts do |t|
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table :comments do |t|
|
23
|
+
t.integer post_id
|
24
|
+
# ... whatever ...
|
25
|
+
end
|
26
|
+
|
27
|
+
Then SchemaAssociations will define the corresponding associations:
|
28
|
+
|
29
|
+
Post.has_many :comments
|
30
|
+
Comment.belongs_to :post
|
31
|
+
|
32
|
+
|
33
|
+
== What if I want something special?
|
34
|
+
|
35
|
+
You're always free to define associations yourself, if for example you want
|
36
|
+
to pass special options. SchemaAssociations won't clobber any existing
|
37
|
+
definitions.
|
38
|
+
|
39
|
+
You can also control the behavior with various options, globally via
|
40
|
+
SchemaAssociations.setup or per-model via #schema_associations. See
|
41
|
+
SchemaAssociations::Config for the available options.
|
42
|
+
|
43
|
+
== Full details
|
44
|
+
|
45
|
+
=== The basics
|
46
|
+
|
47
|
+
=== Multiple references
|
48
|
+
|
49
|
+
=== Concise names
|
50
|
+
|
51
|
+
=== How do I know what it did?
|
52
|
+
|
53
|
+
== Compatibility
|
54
|
+
|
55
|
+
SchemaAssociations supports all combinations of:
|
56
|
+
* rails 3.0 or 3.1
|
57
|
+
* MRI ruby 1.8.7 or 1.9.2
|
58
|
+
|
59
|
+
== Installation
|
60
|
+
|
61
|
+
Install from http://rubygems.org via
|
62
|
+
|
63
|
+
$ gem install "schema_associations"
|
64
|
+
|
65
|
+
or in a Gemfile
|
66
|
+
|
67
|
+
gem "schema_associations"
|
68
|
+
|
69
|
+
== History
|
70
|
+
|
71
|
+
* SchemaAssociations is derived from the "Red Hill On Rails" plugin
|
72
|
+
foreign_key_associations originally created by harukizaemon
|
73
|
+
(https://github.com/harukizaemon)
|
74
|
+
|
75
|
+
* SchemaAssociations was created in 2011 by Michal Lomnicki and Ronen Barzel
|
76
|
+
|
77
|
+
== Testing
|
78
|
+
|
79
|
+
SchemaAssociations is tested using rspec and sqlite3. To run the tests, after you've forked & cloned:
|
80
|
+
|
81
|
+
$ cd schema_associations
|
82
|
+
$ bundle install
|
83
|
+
$ rake spec
|
84
|
+
|
85
|
+
If you're running ruby 1.9.2, code coverage results will be in coverage/index.html -- it should be at 100% coverage.
|
86
|
+
|
87
|
+
== License
|
88
|
+
|
89
|
+
This plugin is released under the MIT license.
|
data/Rakefile
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
6
|
+
spec.rspec_opts = '-Ispec'
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
task :default => :spec
|
11
|
+
|
12
|
+
require 'rake/rdoctask'
|
13
|
+
Rake::RDocTask.new do |rdoc|
|
14
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
15
|
+
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = "schema_associations #{version}"
|
18
|
+
rdoc.rdoc_files.include('README*')
|
19
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
20
|
+
end
|
21
|
+
|
22
|
+
namespace :postgresql do
|
23
|
+
desc 'Build the PostgreSQL test databases'
|
24
|
+
task :build_databases do
|
25
|
+
%x( createdb -E UTF8 schema_associations_unittest )
|
26
|
+
end
|
27
|
+
|
28
|
+
desc 'Drop the PostgreSQL test databases'
|
29
|
+
task :drop_databases do
|
30
|
+
%x( dropdb schema_associations_unittest )
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'Rebuild the PostgreSQL test databases'
|
34
|
+
task :rebuild_databases => [:drop_databases, :build_databases]
|
35
|
+
end
|
36
|
+
|
37
|
+
task :build_postgresql_databases => 'postgresql:build_databases'
|
38
|
+
task :drop_postgresql_databases => 'postgresql:drop_databases'
|
39
|
+
task :rebuild_postgresql_databases => 'postgresql:rebuild_databases'
|
40
|
+
|
41
|
+
MYSQL_DB_USER = 'schema_assoc'
|
42
|
+
namespace :mysql do
|
43
|
+
desc 'Build the MySQL test databases'
|
44
|
+
task :build_databases do
|
45
|
+
%x( echo "create DATABASE schema_associations_unittest DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci " | mysql --user=#{MYSQL_DB_USER})
|
46
|
+
end
|
47
|
+
|
48
|
+
desc 'Drop the MySQL test databases'
|
49
|
+
task :drop_databases do
|
50
|
+
%x( mysqladmin --user=#{MYSQL_DB_USER} -f drop schema_associations_unittest )
|
51
|
+
end
|
52
|
+
|
53
|
+
desc 'Rebuild the MySQL test databases'
|
54
|
+
task :rebuild_databases => [:drop_databases, :build_databases]
|
55
|
+
end
|
56
|
+
|
57
|
+
task :build_mysql_databases => 'mysql:build_databases'
|
58
|
+
task :drop_mysql_databases => 'mysql:drop_databases'
|
59
|
+
task :rebuild_mysql_databases => 'mysql:rebuild_databases'
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'schema_associations' unless defined?(SchemaAssociations)
|
@@ -0,0 +1,223 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module SchemaAssociations
|
4
|
+
module ActiveRecord
|
5
|
+
module Associations #:nodoc:
|
6
|
+
|
7
|
+
module Relation #:nodoc:
|
8
|
+
def self.included(base)
|
9
|
+
base.alias_method_chain :initialize, :schema_associations
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize_with_schema_associations(klass, *args)
|
13
|
+
klass.send :_load_schema_associations_associations
|
14
|
+
initialize_without_schema_associations(klass, *args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.extended(base) #:nodoc:
|
19
|
+
class << base
|
20
|
+
alias_method_chain :reflect_on_association, :schema_associations
|
21
|
+
alias_method_chain :reflect_on_all_associations, :schema_associations
|
22
|
+
end
|
23
|
+
::ActiveRecord::Relation.send :include, Relation
|
24
|
+
end
|
25
|
+
|
26
|
+
def reflect_on_association_with_schema_associations(*args) #:nodoc:
|
27
|
+
_load_schema_associations_associations
|
28
|
+
reflect_on_association_without_schema_associations(*args)
|
29
|
+
end
|
30
|
+
|
31
|
+
def reflect_on_all_associations_with_schema_associations(*args) #:nodoc:
|
32
|
+
_load_schema_associations_associations
|
33
|
+
reflect_on_all_associations_without_schema_associations(*args)
|
34
|
+
end
|
35
|
+
|
36
|
+
def define_attribute_methods(*args) #:nodoc:
|
37
|
+
super
|
38
|
+
_load_schema_associations_associations
|
39
|
+
end
|
40
|
+
|
41
|
+
# Per-model override of Config options. Use via, e.g.
|
42
|
+
# class MyModel < ActiveRecord::Base
|
43
|
+
# schema_associations :auto_create => false
|
44
|
+
# end
|
45
|
+
def schema_associations(opts)
|
46
|
+
@schema_associations_config = SchemaAssociations.config.merge(opts)
|
47
|
+
end
|
48
|
+
|
49
|
+
def schema_associations_config # :nodoc:
|
50
|
+
@schema_associations_config ||= SchemaAssociations.config.dup
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def _load_schema_associations_associations #:nodoc:
|
56
|
+
return if @schema_associations_associations_loaded
|
57
|
+
@schema_associations_associations_loaded = true
|
58
|
+
return unless schema_associations_config.auto_create?
|
59
|
+
|
60
|
+
reverse_foreign_keys.each do | foreign_key |
|
61
|
+
if foreign_key.table_name =~ /^#{table_name}_(.*)$/ || foreign_key.table_name =~ /^(.*)_#{table_name}$/
|
62
|
+
other_table = $1
|
63
|
+
if other_table == other_table.pluralize and connection.columns(foreign_key.table_name).any?{|col| col.name == "#{other_table.singularize}_id"}
|
64
|
+
_define_association(:has_and_belongs_to_many, foreign_key, other_table)
|
65
|
+
else
|
66
|
+
_define_association(:has_one_or_many, foreign_key)
|
67
|
+
end
|
68
|
+
else
|
69
|
+
_define_association(:has_one_or_many, foreign_key)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
foreign_keys.each do | foreign_key |
|
74
|
+
_define_association(:belongs_to, foreign_key)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def _define_association(macro, fk, referencing_table_name = nil) #:nodoc:
|
79
|
+
return unless fk.column_names.size == 1
|
80
|
+
|
81
|
+
referencing_table_name ||= fk.table_name
|
82
|
+
|
83
|
+
column_name = fk.column_names.first
|
84
|
+
reference_name = column_name.sub(/_id$/, '')
|
85
|
+
references_name = fk.references_table_name.singularize
|
86
|
+
referencing_name = referencing_table_name.singularize
|
87
|
+
|
88
|
+
references_class_name = references_name.classify
|
89
|
+
referencing_class_name = referencing_name.classify
|
90
|
+
|
91
|
+
references_concise = _concise_name(references_name, referencing_name)
|
92
|
+
referencing_concise = _concise_name(referencing_name, references_name)
|
93
|
+
|
94
|
+
case reference_name
|
95
|
+
when 'parent'
|
96
|
+
belongs_to = 'parent'
|
97
|
+
belongs_to_concise = 'parent'
|
98
|
+
|
99
|
+
has_one = 'child'
|
100
|
+
has_one_concise = 'child'
|
101
|
+
|
102
|
+
has_many = 'children'
|
103
|
+
has_many_concise = 'children'
|
104
|
+
|
105
|
+
when references_name
|
106
|
+
belongs_to = references_name
|
107
|
+
belongs_to_concise = references_concise
|
108
|
+
|
109
|
+
has_one = referencing_name
|
110
|
+
has_one_concise = referencing_concise
|
111
|
+
|
112
|
+
has_many = referencing_name.pluralize
|
113
|
+
has_many_concise = referencing_concise.pluralize
|
114
|
+
|
115
|
+
when /(.*)_#{references_name}$/, /(.*)_#{references_concise}$/
|
116
|
+
label = $1
|
117
|
+
belongs_to = "#{label}_#{references_name}"
|
118
|
+
belongs_to_concise = "#{label}_#{references_concise}"
|
119
|
+
|
120
|
+
has_one = "#{referencing_name}_as_#{label}"
|
121
|
+
has_one_concise = "#{referencing_concise}_as_#{label}"
|
122
|
+
|
123
|
+
has_many = "#{referencing_name.pluralize}_as_#{label}"
|
124
|
+
has_many_concise = "#{referencing_concise.pluralize}_as_#{label}"
|
125
|
+
|
126
|
+
when /^#{references_name}_(.*)$/, /^#{references_concise}_(.*)$/
|
127
|
+
label = $1
|
128
|
+
belongs_to = "#{references_name}_#{label}"
|
129
|
+
belongs_to_concise = "#{references_concise}_#{label}"
|
130
|
+
|
131
|
+
has_one = "#{referencing_name}_as_#{label}"
|
132
|
+
has_one_concise = "#{referencing_concise}_as_#{label}"
|
133
|
+
|
134
|
+
has_many = "#{referencing_name.pluralize}_as_#{label}"
|
135
|
+
has_many_concise = "#{referencing_concise.pluralize}_as_#{label}"
|
136
|
+
|
137
|
+
else
|
138
|
+
belongs_to = reference_name
|
139
|
+
belongs_to_concise = reference_name
|
140
|
+
|
141
|
+
has_one = "#{referencing_name}_as_#{reference_name}"
|
142
|
+
has_one_concise = "#{referencing_concise}_as_#{reference_name}"
|
143
|
+
|
144
|
+
has_many = "#{referencing_name.pluralize}_as_#{reference_name}"
|
145
|
+
has_many_concise = "#{referencing_concise.pluralize}_as_#{reference_name}"
|
146
|
+
end
|
147
|
+
|
148
|
+
case macro
|
149
|
+
when :has_and_belongs_to_many
|
150
|
+
name = has_many
|
151
|
+
name_concise = has_many_concise
|
152
|
+
opts = {:class_name => referencing_class_name, :join_table => fk.table_name, :foreign_key => column_name}
|
153
|
+
when :belongs_to
|
154
|
+
name = belongs_to
|
155
|
+
name_concise = belongs_to_concise
|
156
|
+
opts = {:class_name => references_class_name, :foreign_key => column_name}
|
157
|
+
when :has_one_or_many
|
158
|
+
opts = {:class_name => referencing_class_name, :foreign_key => column_name}
|
159
|
+
# use connection.indexes and connection.colums rather than class
|
160
|
+
# methods of the referencing class because using the class
|
161
|
+
# methods would require getting the class -- which might trigger
|
162
|
+
# an autoload which could start some recursion making things much
|
163
|
+
# harder to debug.
|
164
|
+
if connection.indexes(referencing_table_name, "#{referencing_table_name} Indexes").any?{|index| index.unique && index.columns == [column_name]}
|
165
|
+
macro = :has_one
|
166
|
+
name = has_one
|
167
|
+
name_concise = has_one_concise
|
168
|
+
else
|
169
|
+
macro = :has_many
|
170
|
+
name = has_many
|
171
|
+
name_concise = has_many_concise
|
172
|
+
if connection.columns(referencing_table_name, "#{referencing_table_name} Columns").any?{ |col| col.name == 'position' }
|
173
|
+
opts[:order] = :position
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
name = name_concise if _use_concise_name?
|
178
|
+
name = name.to_sym
|
179
|
+
if (_filter_association(macro, name) && !_method_exists?(name))
|
180
|
+
logger.info "[schema_associations] #{self.name || self.table_name.classify}.#{macro} #{name.inspect}, #{opts.inspect[1...-1]}"
|
181
|
+
send macro, name, opts.dup
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def _concise_name(string, other) #:nodoc:
|
186
|
+
case
|
187
|
+
when string =~ /^#{other}_(.*)$/ then $1
|
188
|
+
when string =~ /(.*)_#{other}$/ then $1
|
189
|
+
when leader = _common_leader(string,other) then string[leader.length, string.length-leader.length]
|
190
|
+
else string
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def _common_leader(string, other) #:nodoc:
|
195
|
+
leader = nil
|
196
|
+
other.split('_').each do |part|
|
197
|
+
test = "#{leader}#{part}_"
|
198
|
+
break unless string.start_with? test
|
199
|
+
leader = test
|
200
|
+
end
|
201
|
+
return leader
|
202
|
+
end
|
203
|
+
|
204
|
+
def _use_concise_name? #:nodoc:
|
205
|
+
schema_associations_config.concise_names?
|
206
|
+
end
|
207
|
+
|
208
|
+
def _filter_association(macro, name) #:nodoc:
|
209
|
+
config = schema_associations_config
|
210
|
+
return false if config.only and not Array.wrap(config.only).include?(name)
|
211
|
+
return false if config.except and Array.wrap(config.except).include?(name)
|
212
|
+
return false if config.only_type and not Array.wrap(config.only_type).include?(macro)
|
213
|
+
return false if config.except_type and Array.wrap(config.except_type).include?(macro)
|
214
|
+
return true
|
215
|
+
end
|
216
|
+
|
217
|
+
def _method_exists?(name) #:nodoc:
|
218
|
+
method_defined?(name) || private_method_defined?(name) and not (name == :type && [Object, Kernel].include?(instance_method(:type).owner))
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'schema_plus'
|
2
|
+
require 'valuable'
|
3
|
+
|
4
|
+
require 'schema_associations/version'
|
5
|
+
require 'schema_associations/active_record/associations'
|
6
|
+
require 'schema_associations/railtie' if defined?(Rails)
|
7
|
+
|
8
|
+
module SchemaAssociations
|
9
|
+
|
10
|
+
# The configuation options for SchemaAssociations. Set them globally in
|
11
|
+
# +config/initializers/schema_associations.rb+, e.g.:
|
12
|
+
#
|
13
|
+
# SchemaAssociations.setup do |config|
|
14
|
+
# config.concise_names = false
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# or override them per-model, e.g.:
|
18
|
+
#
|
19
|
+
# class MyModel < ActiveRecord::Base
|
20
|
+
# schema_associations.config :concise_names => false
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
class Config < Valuable
|
24
|
+
|
25
|
+
##
|
26
|
+
# :attr_accessor: auto_create
|
27
|
+
#
|
28
|
+
# Whether to automatically create associations based on foreign keys.
|
29
|
+
# Boolean, default is +true+.
|
30
|
+
has_value :auto_create, :klass => :boolean, :default => true
|
31
|
+
|
32
|
+
##
|
33
|
+
# :attr_accessor: concise_names
|
34
|
+
#
|
35
|
+
# Whether to use concise naming (strip out common prefixes from class names).
|
36
|
+
# Boolean, default is +true+.
|
37
|
+
has_value :concise_names, :klass => :boolean, :default => true
|
38
|
+
|
39
|
+
##
|
40
|
+
# :attr_accessor: except
|
41
|
+
#
|
42
|
+
# List of association names to exclude from automatic creation.
|
43
|
+
# Value is a single name, an array of names, or +nil+. Default is +nil+.
|
44
|
+
has_value :except, :default => nil
|
45
|
+
|
46
|
+
##
|
47
|
+
# :attr_accessor: only
|
48
|
+
#
|
49
|
+
# List of association names to include in automatic creation.
|
50
|
+
# Value is a single name, and array of names, or +nil+. Default is +nil+.
|
51
|
+
has_value :only, :default => nil
|
52
|
+
|
53
|
+
##
|
54
|
+
# :attr_accessor: except_type
|
55
|
+
#
|
56
|
+
# List of association types to exclude from automatic creation.
|
57
|
+
# Value is one or an array of +:belongs_to+, +:has_many+, +:has_one+, and/or
|
58
|
+
# +:has_and_belongs_to_many+, or +nil+. Default is +nil+.
|
59
|
+
has_value :except_type, :default => nil
|
60
|
+
|
61
|
+
##
|
62
|
+
# :attr_accessor: only_type
|
63
|
+
#
|
64
|
+
# List of association types to include from automatic creation.
|
65
|
+
# Value is one or an array of +:belongs_to+, +:has_many+, +:has_one+, and/or
|
66
|
+
# +:has_and_belongs_to_many+, or +nil+. Default is +nil+.
|
67
|
+
has_value :only_type, :default => nil
|
68
|
+
|
69
|
+
def dup #:nodoc:
|
70
|
+
self.class.new(Hash[attributes.collect{ |key, val| [key, Valuable === val ? val.class.new(val.attributes) : val] }])
|
71
|
+
end
|
72
|
+
|
73
|
+
def update_attributes(opts)#:nodoc:
|
74
|
+
opts = opts.dup
|
75
|
+
opts.keys.each { |key| self.send(key).update_attributes(opts.delete(key)) if self.class.attributes.include? key and Hash === opts[key] }
|
76
|
+
super(opts)
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def merge(opts)#:nodoc:
|
81
|
+
dup.update_attributes(opts)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns the global configuration, i.e., the singleton instance of Config
|
87
|
+
def self.config
|
88
|
+
@config ||= Config.new
|
89
|
+
end
|
90
|
+
|
91
|
+
# Initialization block is passed a global Config instance that can be
|
92
|
+
# used to configure SchemaAssociations behavior. E.g., if you want to
|
93
|
+
# disable automation creation associations put the following in
|
94
|
+
# config/initializers/schema_associations.rb :
|
95
|
+
#
|
96
|
+
# SchemaAssociations.setup do |config|
|
97
|
+
# config.auto_create = false
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
def self.setup # :yields: config
|
101
|
+
yield config
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.insert #:nodoc:
|
105
|
+
return if @inserted
|
106
|
+
@inserted = true
|
107
|
+
::ActiveRecord::Base.extend SchemaAssociations::ActiveRecord::Associations
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
SchemaAssociations.insert unless defined? Rails::Railtie
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "schema_associations/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "schema_associations"
|
7
|
+
s.version = SchemaAssociations::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ronen Barzel", "Michał Łomnicki"]
|
10
|
+
s.email = ["ronen@barzel.org", "michal.lomnicki@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/ronen/schema_associations"
|
12
|
+
s.summary = "ActiveRecord extension that automatically (DRY) creates associations based on the schema"
|
13
|
+
s.description = "SchemaAssociations extends ActiveRecord to automatically create associations by inspecting the database schema. This is more more DRY than the standard behavior, for which in addition to specifying the foreign key in the migration, you must also specify complementary associations in two model files (e.g. a :belongs_to and a :has_many)."
|
14
|
+
|
15
|
+
s.rubyforge_project = "schema_associations"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency("schema_plus")
|
23
|
+
|
24
|
+
s.add_development_dependency("rake", "~> 0.8.7")
|
25
|
+
s.add_development_dependency("rails", ">= 3.1.0.rc1")
|
26
|
+
s.add_development_dependency("rspec")
|
27
|
+
s.add_development_dependency("sqlite3")
|
28
|
+
s.add_development_dependency("simplecov")
|
29
|
+
s.add_development_dependency("simplecov-gem-adapter")
|
30
|
+
s.add_development_dependency("ruby-debug19") if RUBY_VERSION >= "1.9.2"
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "schema_associations/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "schema_associations"
|
7
|
+
s.version = SchemaAssociations::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ronen Barzel", "Michał Łomnicki"]
|
10
|
+
s.email = ["ronen@barzel.org", "michal.lomnicki@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/ronen/schema_associations"
|
12
|
+
s.summary = "ActiveRecord extension that automatically (DRY) creates associations based on the schema"
|
13
|
+
s.description = "SchemaAssociations extends ActiveRecord to automatically create associations by inspecting the database schema. This is more more DRY than the standard behavior, for which in addition to specifying the foreign key in the migration, you must also specify complementary associations in two model files (e.g. a :belongs_to and a :has_many)."
|
14
|
+
|
15
|
+
s.rubyforge_project = "schema_associations"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency("schema_plus")
|
23
|
+
s.add_dependency("valuable")
|
24
|
+
|
25
|
+
s.add_development_dependency("rails", "~> 3.0")
|
26
|
+
s.add_development_dependency("rspec")
|
27
|
+
s.add_development_dependency("pg")
|
28
|
+
s.add_development_dependency("mysql")
|
29
|
+
s.add_development_dependency("mysql2", "0.2.6")
|
30
|
+
s.add_development_dependency("sqlite3")
|
31
|
+
s.add_development_dependency("simplecov")
|
32
|
+
s.add_development_dependency("simplecov-gem-adapter")
|
33
|
+
s.add_development_dependency("ruby-debug19") if RUBY_VERSION >= "1.9.2"
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "schema_associations/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "schema_associations"
|
7
|
+
s.version = SchemaAssociations::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ronen Barzel", "Michał Łomnicki"]
|
10
|
+
s.email = ["ronen@barzel.org", "michal.lomnicki@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/ronen/schema_associations"
|
12
|
+
s.summary = "ActiveRecord extension that automatically (DRY) creates associations based on the schema"
|
13
|
+
s.description = "SchemaAssociations extends ActiveRecord to automatically create associations by inspecting the database schema. This is more more DRY than the standard behavior, for which in addition to specifying the foreign key in the migration, you must also specify complementary associations in two model files (e.g. a :belongs_to and a :has_many)."
|
14
|
+
|
15
|
+
s.rubyforge_project = "schema_associations"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency("schema_plus")
|
23
|
+
s.add_dependency("valuable")
|
24
|
+
|
25
|
+
s.add_development_dependency("rake", "~> 0.8.7")
|
26
|
+
s.add_development_dependency("rails", ">= 3.1.0.rc1")
|
27
|
+
s.add_development_dependency("rspec")
|
28
|
+
s.add_development_dependency("pg")
|
29
|
+
s.add_development_dependency("mysql")
|
30
|
+
s.add_development_dependency("mysql2")
|
31
|
+
s.add_development_dependency("sqlite3")
|
32
|
+
s.add_development_dependency("simplecov")
|
33
|
+
s.add_development_dependency("simplecov-gem-adapter")
|
34
|
+
s.add_development_dependency("ruby-debug19") if RUBY_VERSION >= "1.9.2"
|
35
|
+
end
|
36
|
+
|