schema_plus 0.1.0.pre1
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 +25 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +25 -0
- data/README.rdoc +147 -0
- data/Rakefile +70 -0
- data/init.rb +1 -0
- data/lib/schema_plus/active_record/associations.rb +211 -0
- data/lib/schema_plus/active_record/base.rb +81 -0
- data/lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb +96 -0
- data/lib/schema_plus/active_record/connection_adapters/column.rb +55 -0
- data/lib/schema_plus/active_record/connection_adapters/foreign_key_definition.rb +115 -0
- data/lib/schema_plus/active_record/connection_adapters/index_definition.rb +51 -0
- data/lib/schema_plus/active_record/connection_adapters/mysql_adapter.rb +111 -0
- data/lib/schema_plus/active_record/connection_adapters/postgresql_adapter.rb +163 -0
- data/lib/schema_plus/active_record/connection_adapters/schema_statements.rb +39 -0
- data/lib/schema_plus/active_record/connection_adapters/sqlite3_adapter.rb +78 -0
- data/lib/schema_plus/active_record/connection_adapters/table_definition.rb +130 -0
- data/lib/schema_plus/active_record/migration.rb +220 -0
- data/lib/schema_plus/active_record/schema.rb +27 -0
- data/lib/schema_plus/active_record/schema_dumper.rb +122 -0
- data/lib/schema_plus/active_record/validations.rb +139 -0
- data/lib/schema_plus/railtie.rb +12 -0
- data/lib/schema_plus/version.rb +3 -0
- data/lib/schema_plus.rb +248 -0
- data/schema_plus.gemspec +37 -0
- data/schema_plus.gemspec.rails3.0 +36 -0
- data/schema_plus.gemspec.rails3.1 +36 -0
- data/spec/association_spec.rb +529 -0
- data/spec/connections/mysql/connection.rb +18 -0
- data/spec/connections/mysql2/connection.rb +18 -0
- data/spec/connections/postgresql/connection.rb +15 -0
- data/spec/connections/sqlite3/connection.rb +14 -0
- data/spec/foreign_key_definition_spec.rb +23 -0
- data/spec/foreign_key_spec.rb +142 -0
- data/spec/index_definition_spec.rb +139 -0
- data/spec/index_spec.rb +71 -0
- data/spec/migration_spec.rb +405 -0
- data/spec/models/comment.rb +2 -0
- data/spec/models/post.rb +2 -0
- data/spec/models/user.rb +2 -0
- data/spec/references_spec.rb +78 -0
- data/spec/schema/auto_schema.rb +23 -0
- data/spec/schema/core_schema.rb +21 -0
- data/spec/schema_dumper_spec.rb +167 -0
- data/spec/schema_spec.rb +71 -0
- data/spec/spec_helper.rb +59 -0
- data/spec/support/extensions/active_model.rb +13 -0
- data/spec/support/helpers.rb +16 -0
- data/spec/support/matchers/automatic_foreign_key_matchers.rb +2 -0
- data/spec/support/matchers/have_index.rb +52 -0
- data/spec/support/matchers/reference.rb +66 -0
- data/spec/support/reference.rb +66 -0
- data/spec/validations_spec.rb +294 -0
- data/spec/views_spec.rb +140 -0
- metadata +269 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
module SchemaPlus
|
2
|
+
module ActiveRecord
|
3
|
+
module Schema #:nodoc: all
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def self.extended(base)
|
10
|
+
class << base
|
11
|
+
attr_accessor :defining
|
12
|
+
alias :defining? :defining
|
13
|
+
|
14
|
+
alias_method_chain :define, :schema_plus
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def define_with_schema_plus(info={}, &block)
|
19
|
+
self.defining = true
|
20
|
+
define_without_schema_plus(info, &block)
|
21
|
+
ensure
|
22
|
+
self.defining = false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'tsort'
|
2
|
+
|
3
|
+
module SchemaPlus
|
4
|
+
module ActiveRecord
|
5
|
+
|
6
|
+
# SchemaPlus modifies ActiveRecord's schema dumper to include foreign
|
7
|
+
# key constraints and views.
|
8
|
+
#
|
9
|
+
# Additionally, index and foreign key constraint definitions are dumped
|
10
|
+
# inline in the create_table block. (This is done for elegance, but
|
11
|
+
# also because Sqlite3 does not allow foreign key constraints to be
|
12
|
+
# added to a table after it has been defined.)
|
13
|
+
#
|
14
|
+
# The tables and views are dumped in alphabetical order, subject to
|
15
|
+
# topological sort constraints that a table must be dumped before any
|
16
|
+
# view that references it or table that has a foreign key constaint to
|
17
|
+
# it.
|
18
|
+
#
|
19
|
+
module SchemaDumper
|
20
|
+
|
21
|
+
include TSort
|
22
|
+
|
23
|
+
def self.included(base) #:nodoc:
|
24
|
+
base.class_eval do
|
25
|
+
private
|
26
|
+
alias_method_chain :table, :schema_plus
|
27
|
+
alias_method_chain :tables, :schema_plus
|
28
|
+
alias_method_chain :indexes, :schema_plus
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def tables_with_schema_plus(stream) #:nodoc:
|
35
|
+
@table_dumps = {}
|
36
|
+
@re_view_referent = %r{(?:(?i)FROM|JOIN) \S*\b(#{(@connection.tables + @connection.views).join('|')})\b}
|
37
|
+
begin
|
38
|
+
tables_without_schema_plus(nil)
|
39
|
+
|
40
|
+
@connection.views.each do |view_name|
|
41
|
+
definition = @connection.view_definition(view_name)
|
42
|
+
@table_dumps[view_name] = " create_view #{view_name.inspect}, #{definition.inspect}\n"
|
43
|
+
end
|
44
|
+
|
45
|
+
tsort().each do |table|
|
46
|
+
stream.print @table_dumps[table]
|
47
|
+
end
|
48
|
+
|
49
|
+
ensure
|
50
|
+
@table_dumps = nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def tsort_each_node(&block) #:nodoc:
|
55
|
+
@table_dumps.keys.sort.each(&block)
|
56
|
+
end
|
57
|
+
|
58
|
+
def tsort_each_child(table, &block) #:nodoc:
|
59
|
+
references = if @connection.views.include?(table)
|
60
|
+
@connection.view_definition(table).scan(@re_view_referent).flatten
|
61
|
+
else
|
62
|
+
@connection.foreign_keys(table).collect(&:references_table_name)
|
63
|
+
end
|
64
|
+
references.sort.uniq.each(&block)
|
65
|
+
end
|
66
|
+
|
67
|
+
def table_with_schema_plus(table, ignore) #:nodoc:
|
68
|
+
|
69
|
+
stream = StringIO.new
|
70
|
+
table_without_schema_plus(table, stream)
|
71
|
+
stream.rewind
|
72
|
+
table_dump = stream.read
|
73
|
+
|
74
|
+
if i = (table_dump =~ /^\s*[e]nd\s*$/)
|
75
|
+
stream = StringIO.new
|
76
|
+
dump_indexes(table, stream)
|
77
|
+
dump_foreign_keys(table, stream)
|
78
|
+
stream.rewind
|
79
|
+
table_dump.insert i, stream.read
|
80
|
+
end
|
81
|
+
|
82
|
+
@table_dumps[table] = table_dump
|
83
|
+
end
|
84
|
+
|
85
|
+
def indexes_with_schema_plus(table, stream) #:nodoc:
|
86
|
+
# do nothing. we've already taken care of indexes as part of
|
87
|
+
# dumping the tables
|
88
|
+
end
|
89
|
+
|
90
|
+
def dump_indexes(table, stream) #:nodoc:
|
91
|
+
indexes = @connection.indexes(table)
|
92
|
+
indexes.each do |index|
|
93
|
+
stream.print " t.index"
|
94
|
+
unless index.columns.blank?
|
95
|
+
stream.print " #{index.columns.inspect}, :name => #{index.name.inspect}"
|
96
|
+
stream.print ", :unique => true" if index.unique
|
97
|
+
stream.print ", :kind => \"#{index.kind}\"" unless index.kind.blank?
|
98
|
+
stream.print ", :case_sensitive => false" unless index.case_sensitive?
|
99
|
+
stream.print ", :conditions => #{index.conditions.inspect}" unless index.conditions.blank?
|
100
|
+
index_lengths = index.lengths.compact if index.lengths.is_a?(Array)
|
101
|
+
stream.print ", :length => #{Hash[*index.columns.zip(index.lengths).flatten].inspect}" if index_lengths.present?
|
102
|
+
else
|
103
|
+
stream.print " :name => #{index.name.inspect}"
|
104
|
+
stream.print ", :kind => \"#{index.kind}\"" unless index.kind.blank?
|
105
|
+
stream.print ", :expression => #{index.expression.inspect}"
|
106
|
+
end
|
107
|
+
|
108
|
+
stream.puts
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def dump_foreign_keys(table, stream) #:nodoc:
|
113
|
+
foreign_keys = @connection.foreign_keys(table)
|
114
|
+
foreign_keys.each do |foreign_key|
|
115
|
+
stream.print " "
|
116
|
+
stream.puts foreign_key.to_dump
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module SchemaPlus
|
2
|
+
module ActiveRecord
|
3
|
+
module Validations
|
4
|
+
|
5
|
+
def inherited(klass) #:nodoc:
|
6
|
+
if self == ::ActiveRecord::Base
|
7
|
+
klass.instance_eval do
|
8
|
+
|
9
|
+
# create a callback to load the validations before validation
|
10
|
+
# happens. the callback deletes itself after use (just to
|
11
|
+
# eliminate the callback overhead).
|
12
|
+
before_validation :load_schema_validations
|
13
|
+
private
|
14
|
+
define_method :load_schema_validations do
|
15
|
+
self.class.send :load_schema_validations
|
16
|
+
self.class.skip_callback :validation, :before, :load_schema_validations
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
# Adds schema-based validations to model.
|
24
|
+
# Attributes as well as associations are validated.
|
25
|
+
# For instance if there is column
|
26
|
+
#
|
27
|
+
# <code>email NOT NULL</code>
|
28
|
+
#
|
29
|
+
# defined at database-level it will be translated to
|
30
|
+
#
|
31
|
+
# <code>validates_presence_of :email</code>
|
32
|
+
#
|
33
|
+
# If there is an association named <tt>user</tt>
|
34
|
+
# based on <tt>user_id NOT NULL</tt> it will be translated to
|
35
|
+
#
|
36
|
+
# <code>validates_presence_of :user</code>
|
37
|
+
#
|
38
|
+
# Note it uses the name of association (user) not the column name (user_id).
|
39
|
+
# Only <tt>belongs_to</tt> associations are validated.
|
40
|
+
#
|
41
|
+
# This accepts following options:
|
42
|
+
# * :only - auto-validate only given attributes
|
43
|
+
# * :except - auto-validate all but given attributes
|
44
|
+
#
|
45
|
+
def schema_plus(*) #:nodoc:
|
46
|
+
super
|
47
|
+
load_schema_validations
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def load_schema_validations #:nodoc:
|
53
|
+
# Don't bother if: it's already been loaded; the class is abstract; not a base class; or the table doesn't exist
|
54
|
+
return unless create_schema_validations?
|
55
|
+
|
56
|
+
load_column_validations
|
57
|
+
load_association_validations
|
58
|
+
@schema_validations_loaded = true
|
59
|
+
end
|
60
|
+
|
61
|
+
def load_column_validations #:nodoc:
|
62
|
+
content_columns.each do |column|
|
63
|
+
name = column.name.to_sym
|
64
|
+
|
65
|
+
# Data-type validation
|
66
|
+
if column.type == :integer
|
67
|
+
validate_logged :validates_numericality_of, name, :allow_nil => true, :only_integer => true
|
68
|
+
elsif column.number?
|
69
|
+
validate_logged :validates_numericality_of, name, :allow_nil => true
|
70
|
+
elsif column.text? && column.limit
|
71
|
+
validate_logged :validates_length_of, name, :allow_nil => true, :maximum => column.limit
|
72
|
+
end
|
73
|
+
|
74
|
+
# NOT NULL constraints
|
75
|
+
if column.required_on
|
76
|
+
if column.type == :boolean
|
77
|
+
validate_logged :validates_inclusion_of, name, :in => [true, false], :message => :blank
|
78
|
+
else
|
79
|
+
validate_logged :validates_presence_of, name
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# UNIQUE constraints
|
84
|
+
add_uniqueness_validation(column) if column.unique?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def load_association_validations #:nodoc:
|
89
|
+
reflect_on_all_associations(:belongs_to).each do |association|
|
90
|
+
# :primary_key_name was deprecated (noisily) in rails 3.1
|
91
|
+
foreign_key_method = (association.respond_to? :foreign_key) ? :foreign_key : :primary_key_name
|
92
|
+
column = columns_hash[association.send(foreign_key_method).to_s]
|
93
|
+
next unless column
|
94
|
+
|
95
|
+
# NOT NULL constraints
|
96
|
+
validate_logged :validates_presence_of, association.name if column.required_on
|
97
|
+
|
98
|
+
# UNIQUE constraints
|
99
|
+
add_uniqueness_validation(column) if column.unique?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def add_uniqueness_validation(column) #:nodoc:
|
104
|
+
scope = column.unique_scope.map(&:to_sym)
|
105
|
+
condition = :"#{column.name}_changed?"
|
106
|
+
name = column.name.to_sym
|
107
|
+
validate_logged :validates_uniqueness_of, name, :scope => scope, :allow_nil => true, :if => condition
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_schema_validations? #:nodoc:
|
111
|
+
schema_plus_config.validations.auto_create? && !(@schema_validations_loaded || abstract_class? || name.blank? || !table_exists?)
|
112
|
+
end
|
113
|
+
|
114
|
+
def validate_logged(method, arg, opts={}) #:nodoc:
|
115
|
+
if _filter_validation(method, arg)
|
116
|
+
msg = "SchemaPlus validations: #{self.name}.#{method} #{arg.inspect}"
|
117
|
+
msg += ", #{opts.inspect[1...-1]}" if opts.any?
|
118
|
+
logger.info msg
|
119
|
+
send method, arg, opts
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def _filter_validation(macro, name) #:nodoc:
|
124
|
+
config = schema_plus_config.validations
|
125
|
+
types = [macro]
|
126
|
+
if match = macro.to_s.match(/^validates_(.*)_of$/)
|
127
|
+
types << match[1].to_sym
|
128
|
+
end
|
129
|
+
return false if config.only and not Array.wrap(config.only).include?(name)
|
130
|
+
return false if config.except and Array.wrap(config.except).include?(name)
|
131
|
+
return false if config.only_type and not (Array.wrap(config.only_type) & types).any?
|
132
|
+
return false if config.except_type and (Array.wrap(config.except_type) & types).any?
|
133
|
+
return true
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
data/lib/schema_plus.rb
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
require 'valuable'
|
2
|
+
|
3
|
+
require 'schema_plus/version'
|
4
|
+
require 'schema_plus/active_record/base'
|
5
|
+
require 'schema_plus/active_record/migration'
|
6
|
+
require 'schema_plus/active_record/connection_adapters/table_definition'
|
7
|
+
require 'schema_plus/active_record/connection_adapters/schema_statements'
|
8
|
+
require 'schema_plus/active_record/schema'
|
9
|
+
require 'schema_plus/active_record/schema_dumper'
|
10
|
+
require 'schema_plus/active_record/connection_adapters/abstract_adapter'
|
11
|
+
require 'schema_plus/active_record/connection_adapters/column'
|
12
|
+
require 'schema_plus/active_record/connection_adapters/foreign_key_definition'
|
13
|
+
require 'schema_plus/active_record/connection_adapters/index_definition'
|
14
|
+
require 'schema_plus/active_record/associations'
|
15
|
+
require 'schema_plus/railtie' if defined?(Rails)
|
16
|
+
|
17
|
+
module SchemaPlus
|
18
|
+
module ActiveRecord
|
19
|
+
|
20
|
+
autoload :Validations, 'schema_plus/active_record/validations'
|
21
|
+
|
22
|
+
module ConnectionAdapters
|
23
|
+
autoload :MysqlAdapter, 'schema_plus/active_record/connection_adapters/mysql_adapter'
|
24
|
+
autoload :PostgresqlAdapter, 'schema_plus/active_record/connection_adapters/postgresql_adapter'
|
25
|
+
autoload :Sqlite3Adapter, 'schema_plus/active_record/connection_adapters/sqlite3_adapter'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# This global configuation options for SchmeaPlus.
|
30
|
+
# Set them in +config/initializers/schema_plus.rb+ using:
|
31
|
+
#
|
32
|
+
# SchemaPlus.setup do |config|
|
33
|
+
# ...
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# The options are grouped into subsets based on area of functionality.
|
37
|
+
# See Config::ForeignKeys, Config::Associations, Config::Validations
|
38
|
+
#
|
39
|
+
class Config < Valuable
|
40
|
+
|
41
|
+
# This set of configuration options control SchemaPlus's foreign key
|
42
|
+
# constraint behavior. Set them in
|
43
|
+
# +config/initializers/schema_plus.rb+ using:
|
44
|
+
#
|
45
|
+
# SchemaPlus.setup do |config|
|
46
|
+
# config.foreign_keys.auto_create = ...
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
class ForeignKeys < Valuable
|
50
|
+
##
|
51
|
+
# :attr_accessor: auto_create
|
52
|
+
#
|
53
|
+
# Whether to automatically create foreign key constraints for columns
|
54
|
+
# suffixed with +_id+. Boolean, default is +true+.
|
55
|
+
has_value :auto_create, :klass => :boolean, :default => true
|
56
|
+
|
57
|
+
##
|
58
|
+
# :attr_accessor: auto_index
|
59
|
+
#
|
60
|
+
# Whether to automatically create indexes when creating foreign key constraints for columns.
|
61
|
+
# Boolean, default is +true+.
|
62
|
+
has_value :auto_index, :klass => :boolean, :default => true
|
63
|
+
|
64
|
+
##
|
65
|
+
# :attr_accessor: on_update
|
66
|
+
#
|
67
|
+
# The default value for +:on_update+ when creating foreign key
|
68
|
+
# constraints for columns. Valid values are as described in
|
69
|
+
# ForeignKeyDefinition, or +nil+ to let the database connection use
|
70
|
+
# its own default. Default is +nil+.
|
71
|
+
has_value :on_update
|
72
|
+
|
73
|
+
##
|
74
|
+
# :attr_accessor: on_delete
|
75
|
+
#
|
76
|
+
# The default value for +:on_delete+ when creating foreign key
|
77
|
+
# constraints for columns. Valid values are as described in
|
78
|
+
# ForeignKeyDefinition, or +nil+ to let the database connection use
|
79
|
+
# its own default. Default is +nil+.
|
80
|
+
has_value :on_delete
|
81
|
+
end
|
82
|
+
has_value :foreign_keys, :klass => ForeignKeys, :default => ForeignKeys.new
|
83
|
+
|
84
|
+
# This set of configuration options control SchemaPlus's automatic
|
85
|
+
# association behavior. Set them in
|
86
|
+
# +config/initializers/schema_plus.rb+ using:
|
87
|
+
#
|
88
|
+
# SchemaPlus.setup do |config|
|
89
|
+
# config.associations.auto_create = ...
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
class Associations < Valuable
|
93
|
+
|
94
|
+
##
|
95
|
+
# :attr_accessor: auto_create
|
96
|
+
#
|
97
|
+
# Whether to automatically create associations based on foreign keys.
|
98
|
+
# Boolean, default is +true+.
|
99
|
+
has_value :auto_create, :klass => :boolean, :default => true
|
100
|
+
|
101
|
+
##
|
102
|
+
# :attr_accessor: concise_names
|
103
|
+
#
|
104
|
+
# Whether to use concise naming (strip out common prefixes from class names).
|
105
|
+
# Boolean, default is +true+.
|
106
|
+
has_value :concise_names, :klass => :boolean, :default => true
|
107
|
+
|
108
|
+
##
|
109
|
+
# :attr_accessor: except
|
110
|
+
#
|
111
|
+
# List of association names to exclude from automatic creation.
|
112
|
+
# Value is a single name, an array of names, or +nil+. Default is +nil+.
|
113
|
+
has_value :except, :default => nil
|
114
|
+
|
115
|
+
##
|
116
|
+
# :attr_accessor: only
|
117
|
+
#
|
118
|
+
# List of association names to include in automatic creation.
|
119
|
+
# Value is a single name, and array of names, or +nil+. Default is +nil+.
|
120
|
+
has_value :only, :default => nil
|
121
|
+
|
122
|
+
##
|
123
|
+
# :attr_accessor: except_type
|
124
|
+
#
|
125
|
+
# List of association types to exclude from automatic creation.
|
126
|
+
# Value is one or an array of +:belongs_to+, +:has_many+, +:has_one+, and/or
|
127
|
+
# +:has_and_belongs_to_many+, or +nil+. Default is +nil+.
|
128
|
+
has_value :except_type, :default => nil
|
129
|
+
|
130
|
+
##
|
131
|
+
# :attr_accessor: only_type
|
132
|
+
#
|
133
|
+
# List of association types to include from automatic creation.
|
134
|
+
# Value is one or an array of +:belongs_to+, +:has_many+, +:has_one+, and/or
|
135
|
+
# +:has_and_belongs_to_many+, or +nil+. Default is +nil+.
|
136
|
+
has_value :only_type, :default => nil
|
137
|
+
|
138
|
+
end
|
139
|
+
has_value :associations, :klass => Associations, :default => Associations.new
|
140
|
+
|
141
|
+
# This set of configuration options control SchemaPlus's automatic
|
142
|
+
# validations behavior. Set them in
|
143
|
+
# +config/initializers/schema_plus.rb+ using:
|
144
|
+
#
|
145
|
+
# SchemaPlus.setup do |config|
|
146
|
+
# config.validations.auto_create = ...
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
class Validations < Valuable
|
150
|
+
##
|
151
|
+
# :attr_accessor: auto_create
|
152
|
+
#
|
153
|
+
# Whether to automatically create validations based on database constraints.
|
154
|
+
# Boolean, default is +true+.
|
155
|
+
has_value :auto_create, :klass => :boolean, :default => true
|
156
|
+
|
157
|
+
##
|
158
|
+
# :attr_accessor: only
|
159
|
+
#
|
160
|
+
# List of field names to include in automatic validation.
|
161
|
+
# Value is a single name, and array of names, or +nil+. Default is +nil+.
|
162
|
+
has_value :only, :default => nil
|
163
|
+
|
164
|
+
##
|
165
|
+
# :attr_accessor: except
|
166
|
+
#
|
167
|
+
# List of field names to exclude from automatic validation.
|
168
|
+
# Value is a single name, an array of names, or +nil+. Default is <tt>[:created_at, :updated_at, :created_on, :updated_on]</tt>.
|
169
|
+
has_value :except, :default => [:created_at, :updated_at, :created_on, :updated_on]
|
170
|
+
|
171
|
+
##
|
172
|
+
# :attr_accessor: only_type
|
173
|
+
#
|
174
|
+
# List of validation types to exclude from automatic validation.
|
175
|
+
# Value is a single type, and array of types, or +nil+. Default is +nil+.
|
176
|
+
# A type is specified as, e.g., +:validates_presence_of+ or simply +:presence+.
|
177
|
+
has_value :except_type, :default => nil
|
178
|
+
|
179
|
+
##
|
180
|
+
# :attr_accessor: only_type
|
181
|
+
#
|
182
|
+
# List of validation types to include in automatic validation.
|
183
|
+
# Value is a single type, and array of types, or +nil+. Default is +nil+.
|
184
|
+
# A type is specified as, e.g., +:validates_presence_of+ or simply +:presence+.
|
185
|
+
has_value :only_type, :default => nil
|
186
|
+
|
187
|
+
end
|
188
|
+
has_value :validations, :klass => Validations, :default => Validations.new
|
189
|
+
|
190
|
+
|
191
|
+
def dup #:nodoc:
|
192
|
+
self.class.new(Hash[attributes.collect{ |key, val| [key, Valuable === val ? val.class.new(val.attributes) : val] }])
|
193
|
+
end
|
194
|
+
|
195
|
+
def update_attributes(opts)#:nodoc:
|
196
|
+
opts = opts.dup
|
197
|
+
opts.keys.each { |key| self.send(key).update_attributes(opts.delete(key)) if self.class.attributes.include? key and Hash === opts[key] }
|
198
|
+
super(opts)
|
199
|
+
self
|
200
|
+
end
|
201
|
+
|
202
|
+
def merge(opts)#:nodoc:
|
203
|
+
dup.update_attributes(opts)
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
# Returns the global configuration, i.e., the singleton instance of Config
|
209
|
+
def self.config
|
210
|
+
@config ||= Config.new
|
211
|
+
end
|
212
|
+
|
213
|
+
# Initialization block is passed a global Config instance that can be
|
214
|
+
# used to configure SchemaPlus behavior. E.g., if you want to disable
|
215
|
+
# automation creation of foreign key constraints for columns name *_id,
|
216
|
+
# put the following in config/initializers/schema_plus.rb :
|
217
|
+
#
|
218
|
+
# SchemaPlus.setup do |config|
|
219
|
+
# config.foreign_keys.auto_create = false
|
220
|
+
# end
|
221
|
+
#
|
222
|
+
def self.setup # :yields: config
|
223
|
+
yield config
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.insert_connection_adapters #:nodoc:
|
227
|
+
return if @inserted_connection_adapters
|
228
|
+
@inserted_connection_adapters = true
|
229
|
+
::ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::AbstractAdapter)
|
230
|
+
::ActiveRecord::ConnectionAdapters::Column.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::Column)
|
231
|
+
::ActiveRecord::ConnectionAdapters::IndexDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition)
|
232
|
+
# (mysql2 v0.2.7 uses its own IndexDefinition, which is compatible with the monkey patches; so if that constant exists, include the patches
|
233
|
+
::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition) if defined? ::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition
|
234
|
+
::ActiveRecord::ConnectionAdapters::SchemaStatements.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::SchemaStatements)
|
235
|
+
::ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::TableDefinition)
|
236
|
+
end
|
237
|
+
|
238
|
+
def self.insert #:nodoc:
|
239
|
+
return if @inserted
|
240
|
+
@inserted = true
|
241
|
+
insert_connection_adapters
|
242
|
+
::ActiveRecord::Base.send(:include, SchemaPlus::ActiveRecord::Base)
|
243
|
+
::ActiveRecord::Migration.send(:include, SchemaPlus::ActiveRecord::Migration)
|
244
|
+
::ActiveRecord::Schema.send(:include, SchemaPlus::ActiveRecord::Schema)
|
245
|
+
::ActiveRecord::SchemaDumper.send(:include, SchemaPlus::ActiveRecord::SchemaDumper)
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|