schema_plus 0.1.0.pre3 → 0.1.0.pre4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +18 -7
- data/lib/schema_plus/active_record/base.rb +0 -19
- data/lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb +5 -0
- data/lib/schema_plus/active_record/connection_adapters/table_definition.rb +1 -0
- data/lib/schema_plus/railtie.rb +4 -5
- data/lib/schema_plus/version.rb +1 -1
- data/lib/schema_plus.rb +1 -55
- data/runspecs +36 -0
- data/schema_plus.gemspec +11 -2
- data/spec/column_spec.rb +99 -0
- data/spec/connections/mysql/connection.rb +1 -1
- data/spec/connections/mysql2/connection.rb +1 -1
- data/spec/migration_spec.rb +15 -0
- metadata +50 -78
- data/lib/schema_plus/active_record/validations.rb +0 -139
- data/schema_plus.gemspec.rails3.0 +0 -36
- data/schema_plus.gemspec.rails3.1 +0 -36
- data/spec/validations_spec.rb +0 -292
data/README.rdoc
CHANGED
@@ -6,9 +6,7 @@ SchemaPlus is an ActiveRecord extension that provides enhanced capabilities for
|
|
6
6
|
|
7
7
|
For added rails DRYness see also the gems
|
8
8
|
{+schema_associations+}[http://rubygems.org/gems/schema_associations] and
|
9
|
-
{+schema_validations+}[http://rubygems.org/gems/
|
10
|
-
<b>IMPORTANT PRERELEASE NOTE: <i>schema_validations is not yet separate
|
11
|
-
gems, it's currently bundled in here. It's not documented yet though.</i></b>
|
9
|
+
{+schema_validations+}[http://rubygems.org/gems/schema_validations]
|
12
10
|
|
13
11
|
== Compatibility
|
14
12
|
|
@@ -127,26 +125,39 @@ ActiveRecord works with views the same as with ordinary tables. That is, for th
|
|
127
125
|
* Greg Barnett (https://github.com/greg-barnett)
|
128
126
|
* Ronen Barzel (https://github.com/ronen)
|
129
127
|
|
130
|
-
* SchemaPlus was created in 2011 by
|
128
|
+
* SchemaPlus was created in 2011 by Michał Łomnicki and Ronen Barzel
|
131
129
|
|
132
130
|
|
133
131
|
|
134
132
|
== Testing
|
135
133
|
|
136
|
-
SchemaPlus is tested using rspec
|
134
|
+
SchemaPlus is tested using rspec and rvm, with some hackery to test against
|
135
|
+
multiple versions of rails and ruby and db adapters. To run the tests,
|
136
|
+
after you've forked & cloned: Make sure you have Postgresql and MySQL
|
137
|
+
running. Create database user "schema_plus" with permissions for database
|
138
|
+
"schema_plus_unittest". Then:
|
137
139
|
|
138
140
|
$ cd schema_plus
|
139
141
|
$ bundle install
|
140
142
|
$ rake postgresql:build_databases
|
141
143
|
$ rake mysql:build_databases
|
144
|
+
$ ./runspecs --install # do this once to install gem dependencies for all versions (slow)
|
145
|
+
$ ./runspecs # as many times as you like
|
146
|
+
|
147
|
+
You can also pick a specific version of rails and ruby to use, such as:
|
148
|
+
$ rvm use 1.9.2
|
149
|
+
$ export SCHEMA_ASSOCIATIONS_RAILS_VERSION=3.1
|
150
|
+
$ bundle update --local rails mysql2 # different versions of rails require different mysql2's
|
151
|
+
$ rake spec
|
152
|
+
|
153
|
+
And you can run the specs for a specific adapter:
|
142
154
|
$ rake postgresql:spec # to run postgresql tests only
|
143
155
|
$ rake mysql:spec # to run mysql tests only
|
144
156
|
$ rake mysql2:spec # to run mysql2 tests only
|
145
157
|
$ rake sqlite3:spec # to run sqlite3 tests only
|
146
|
-
$ rake spec # run all tests
|
147
158
|
|
148
159
|
If you're running ruby 1.9.2, code coverage results will be in coverage/index.html -- it should be at 100% coverage.
|
149
160
|
|
150
161
|
== License
|
151
162
|
|
152
|
-
This
|
163
|
+
This gem is released under the MIT license.
|
@@ -7,32 +7,18 @@ module SchemaPlus
|
|
7
7
|
module Base
|
8
8
|
def self.included(base) #:nodoc:
|
9
9
|
base.extend(ClassMethods)
|
10
|
-
base.extend(SchemaPlus::ActiveRecord::Validations)
|
11
10
|
end
|
12
11
|
|
13
12
|
module ClassMethods #:nodoc:
|
14
13
|
def self.extended(base) #:nodoc:
|
15
14
|
class << base
|
16
15
|
alias_method_chain :columns, :schema_plus
|
17
|
-
alias_method_chain :abstract_class?, :schema_plus
|
18
16
|
alias_method_chain :reset_column_information, :schema_plus
|
19
17
|
end
|
20
18
|
end
|
21
19
|
|
22
20
|
public
|
23
21
|
|
24
|
-
# Per-model override of Config options. Use via, e.g.
|
25
|
-
# class MyModel < ActiveRecord::Base
|
26
|
-
# schema_plus :associations => { :auto_create => false }
|
27
|
-
# end
|
28
|
-
def schema_plus(opts)
|
29
|
-
@schema_plus_config = SchemaPlus.config.merge(opts)
|
30
|
-
end
|
31
|
-
|
32
|
-
def abstract_class_with_schema_plus? #:nodoc:
|
33
|
-
abstract_class_without_schema_plus? || !(name =~ /^Abstract/).nil?
|
34
|
-
end
|
35
|
-
|
36
22
|
def columns_with_schema_plus #:nodoc:
|
37
23
|
unless @schema_plus_extended_columns
|
38
24
|
@schema_plus_extended_columns = true
|
@@ -69,11 +55,6 @@ module SchemaPlus
|
|
69
55
|
connection.reverse_foreign_keys(table_name, "#{name} Reverse Foreign Keys")
|
70
56
|
end
|
71
57
|
|
72
|
-
private
|
73
|
-
|
74
|
-
def schema_plus_config # :nodoc:
|
75
|
-
@schema_plus_config ||= SchemaPlus.config.dup
|
76
|
-
end
|
77
58
|
end
|
78
59
|
end
|
79
60
|
end
|
@@ -35,6 +35,11 @@ module SchemaPlus
|
|
35
35
|
adapter_module = SchemaPlus::ActiveRecord::ConnectionAdapters.const_get(adapter)
|
36
36
|
self.class.send(:include, adapter_module) unless self.class.include?(adapter_module)
|
37
37
|
self.post_initialize if self.respond_to? :post_initialize
|
38
|
+
# rails 3.1 defines a separate Mysql2IndexDefinition which is
|
39
|
+
# compatible with the monkey patches; but the definition only
|
40
|
+
# appears once the adapter is loaded. so wait til now to check
|
41
|
+
# if that constant exists, then include the patches
|
42
|
+
::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition) if defined? ::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition
|
38
43
|
end
|
39
44
|
end
|
40
45
|
|
@@ -118,6 +118,7 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
|
|
118
118
|
protected
|
119
119
|
def column_index(name, options) #:nodoc:
|
120
120
|
options = {} if options == true
|
121
|
+
options = {:unique => true} if options == :unique
|
121
122
|
name = [name] + Array.wrap(options.delete(:with)).compact
|
122
123
|
self.index(name, options)
|
123
124
|
end
|
data/lib/schema_plus/railtie.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
module SchemaPlus
|
2
2
|
class Railtie < Rails::Railtie #:nodoc:
|
3
|
-
config.before_initialize do
|
4
|
-
SchemaPlus.insert_connection_adapters
|
5
|
-
end
|
6
3
|
|
7
|
-
initializer 'schema_plus.insert', :after =>
|
8
|
-
|
4
|
+
initializer 'schema_plus.insert', :after => "active_record.initialize_database" do
|
5
|
+
ActiveSupport.on_load(:active_record) do
|
6
|
+
SchemaPlus.insert
|
7
|
+
end
|
9
8
|
end
|
10
9
|
|
11
10
|
end
|
data/lib/schema_plus/version.rb
CHANGED
data/lib/schema_plus.rb
CHANGED
@@ -16,8 +16,6 @@ require 'schema_plus/railtie' if defined?(Rails)
|
|
16
16
|
module SchemaPlus
|
17
17
|
module ActiveRecord
|
18
18
|
|
19
|
-
autoload :Validations, 'schema_plus/active_record/validations'
|
20
|
-
|
21
19
|
module ConnectionAdapters
|
22
20
|
autoload :MysqlAdapter, 'schema_plus/active_record/connection_adapters/mysql_adapter'
|
23
21
|
autoload :PostgresqlAdapter, 'schema_plus/active_record/connection_adapters/postgresql_adapter'
|
@@ -33,7 +31,7 @@ module SchemaPlus
|
|
33
31
|
# end
|
34
32
|
#
|
35
33
|
# The options are grouped into subsets based on area of functionality.
|
36
|
-
# See Config::ForeignKeys
|
34
|
+
# See Config::ForeignKeys
|
37
35
|
#
|
38
36
|
class Config < Valuable
|
39
37
|
|
@@ -80,56 +78,6 @@ module SchemaPlus
|
|
80
78
|
end
|
81
79
|
has_value :foreign_keys, :klass => ForeignKeys, :default => ForeignKeys.new
|
82
80
|
|
83
|
-
# This set of configuration options control SchemaPlus's automatic
|
84
|
-
# validations behavior. Set them in
|
85
|
-
# +config/initializers/schema_plus.rb+ using:
|
86
|
-
#
|
87
|
-
# SchemaPlus.setup do |config|
|
88
|
-
# config.validations.auto_create = ...
|
89
|
-
# end
|
90
|
-
#
|
91
|
-
class Validations < Valuable
|
92
|
-
##
|
93
|
-
# :attr_accessor: auto_create
|
94
|
-
#
|
95
|
-
# Whether to automatically create validations based on database constraints.
|
96
|
-
# Boolean, default is +true+.
|
97
|
-
has_value :auto_create, :klass => :boolean, :default => true
|
98
|
-
|
99
|
-
##
|
100
|
-
# :attr_accessor: only
|
101
|
-
#
|
102
|
-
# List of field names to include in automatic validation.
|
103
|
-
# Value is a single name, and array of names, or +nil+. Default is +nil+.
|
104
|
-
has_value :only, :default => nil
|
105
|
-
|
106
|
-
##
|
107
|
-
# :attr_accessor: except
|
108
|
-
#
|
109
|
-
# List of field names to exclude from automatic validation.
|
110
|
-
# Value is a single name, an array of names, or +nil+. Default is <tt>[:created_at, :updated_at, :created_on, :updated_on]</tt>.
|
111
|
-
has_value :except, :default => [:created_at, :updated_at, :created_on, :updated_on]
|
112
|
-
|
113
|
-
##
|
114
|
-
# :attr_accessor: only_type
|
115
|
-
#
|
116
|
-
# List of validation types to exclude from automatic validation.
|
117
|
-
# Value is a single type, and array of types, or +nil+. Default is +nil+.
|
118
|
-
# A type is specified as, e.g., +:validates_presence_of+ or simply +:presence+.
|
119
|
-
has_value :except_type, :default => nil
|
120
|
-
|
121
|
-
##
|
122
|
-
# :attr_accessor: only_type
|
123
|
-
#
|
124
|
-
# List of validation types to include in automatic validation.
|
125
|
-
# Value is a single type, and array of types, or +nil+. Default is +nil+.
|
126
|
-
# A type is specified as, e.g., +:validates_presence_of+ or simply +:presence+.
|
127
|
-
has_value :only_type, :default => nil
|
128
|
-
|
129
|
-
end
|
130
|
-
has_value :validations, :klass => Validations, :default => Validations.new
|
131
|
-
|
132
|
-
|
133
81
|
def dup #:nodoc:
|
134
82
|
self.class.new(Hash[attributes.collect{ |key, val| [key, Valuable === val ? val.class.new(val.attributes) : val] }])
|
135
83
|
end
|
@@ -171,8 +119,6 @@ module SchemaPlus
|
|
171
119
|
::ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::AbstractAdapter)
|
172
120
|
::ActiveRecord::ConnectionAdapters::Column.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::Column)
|
173
121
|
::ActiveRecord::ConnectionAdapters::IndexDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition)
|
174
|
-
# (mysql2 v0.2.7 uses its own IndexDefinition, which is compatible with the monkey patches; so if that constant exists, include the patches
|
175
|
-
::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition) if defined? ::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition
|
176
122
|
::ActiveRecord::ConnectionAdapters::SchemaStatements.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::SchemaStatements)
|
177
123
|
::ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::TableDefinition)
|
178
124
|
end
|
data/runspecs
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
RUBY_VERSIONS = %W[1.8.7 1.9.2]
|
6
|
+
RAILS_VERSIONS = %W[3.0 3.1]
|
7
|
+
|
8
|
+
options = {}
|
9
|
+
OptionParser.new do |opts|
|
10
|
+
opts.banner = "Usage: #{$0} [options]"
|
11
|
+
|
12
|
+
opts.on("--install", "Install gem dependencies") do |v|
|
13
|
+
options[:install] = v
|
14
|
+
end
|
15
|
+
end.parse!
|
16
|
+
|
17
|
+
cmds = if options [:install]
|
18
|
+
['bundle update']
|
19
|
+
else
|
20
|
+
['bundle update --local rails mysql2 | egrep "rails|mysql2"', 'rake spec']
|
21
|
+
end
|
22
|
+
|
23
|
+
n = 1
|
24
|
+
total = RUBY_VERSIONS.size * RAILS_VERSIONS.size
|
25
|
+
RUBY_VERSIONS.each do |ruby|
|
26
|
+
RAILS_VERSIONS.each do |rails|
|
27
|
+
puts "\n\n*** ruby version #{ruby} - rails version #{rails} [#{n} of #{total}]\n\n"
|
28
|
+
n += 1
|
29
|
+
allcmds = []
|
30
|
+
allcmds << "rvm use #{ruby}"
|
31
|
+
allcmds << "export SCHEMA_PLUS_RAILS_VERSION=#{rails}"
|
32
|
+
allcmds += cmds
|
33
|
+
allcmds << 'exit'
|
34
|
+
system %Q{echo '#{allcmds.join(' \n ')}' | bash -i} or abort "aborting #{$0}"
|
35
|
+
end
|
36
|
+
end
|
data/schema_plus.gemspec
CHANGED
@@ -23,12 +23,21 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_dependency("rails")
|
24
24
|
s.add_dependency("valuable")
|
25
25
|
|
26
|
+
case ENV['SCHEMA_PLUS_RAILS_VERSION']
|
27
|
+
when '3.0'
|
28
|
+
s.add_development_dependency("rails", "~> 3.0")
|
29
|
+
s.add_development_dependency("mysql2", "~> 0.2.6")
|
30
|
+
when '3.1'
|
31
|
+
s.add_development_dependency("rails", ">= 3.1.0.rc1")
|
32
|
+
s.add_development_dependency("mysql2")
|
33
|
+
else
|
34
|
+
s.add_development_dependency("mysql2")
|
35
|
+
end
|
36
|
+
|
26
37
|
s.add_development_dependency("rake", "~> 0.8.7")
|
27
|
-
s.add_development_dependency("rails", ">= 3.1.0.rc1")
|
28
38
|
s.add_development_dependency("rspec")
|
29
39
|
s.add_development_dependency("pg")
|
30
40
|
s.add_development_dependency("mysql")
|
31
|
-
s.add_development_dependency("mysql2")
|
32
41
|
s.add_development_dependency("sqlite3")
|
33
42
|
s.add_development_dependency("simplecov")
|
34
43
|
s.add_development_dependency("simplecov-gem-adapter")
|
data/spec/column_spec.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
require 'models/user'
|
4
|
+
|
5
|
+
describe "Column" do
|
6
|
+
let(:migration) { ::ActiveRecord::Migration }
|
7
|
+
|
8
|
+
context "regarding indexes" do
|
9
|
+
|
10
|
+
context "if not unique" do
|
11
|
+
|
12
|
+
before (:each) do
|
13
|
+
create_table(User, :login => { :index => true})
|
14
|
+
@login = User.columns.find{|column| column.name == "login"}
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should report not unique" do
|
18
|
+
@login.should_not be_unique
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should report nil unique scope" do
|
22
|
+
create_table(User, :login => { :index => true})
|
23
|
+
@login.unique_scope.should be_nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "if unique single column" do
|
28
|
+
before (:each) do
|
29
|
+
create_table(User, :login => { :index => :unique})
|
30
|
+
@login = User.columns.find{|column| column.name == "login"}
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should report unique" do
|
34
|
+
@login.should be_unique
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should report an empty unique scope" do
|
38
|
+
@login.unique_scope.should == []
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "if unique multicolumn" do
|
43
|
+
|
44
|
+
before (:each) do
|
45
|
+
create_table(User, :first => {}, :middle => {}, :last => { :index => {:with => [:first, :middle], :unique => true}})
|
46
|
+
@first = User.columns.find{|column| column.name == "first"}
|
47
|
+
@middle = User.columns.find{|column| column.name == "middle"}
|
48
|
+
@last = User.columns.find{|column| column.name == "last"}
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should report unique for each" do
|
52
|
+
@first.should be_unique
|
53
|
+
@middle.should be_unique
|
54
|
+
@last.should be_unique
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should report unique scope for each" do
|
58
|
+
@first.unique_scope.should =~ %W[middle last]
|
59
|
+
@middle.unique_scope.should =~ %W[first last]
|
60
|
+
@last.unique_scope.should =~ %W[first middle]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
context "regarding when it requires a value" do
|
67
|
+
|
68
|
+
it "not required if the column can be null" do
|
69
|
+
create_table(User, :login => { :null => true})
|
70
|
+
User.columns.find{|column| column.name == "login"}.required_on.should be_nil
|
71
|
+
end
|
72
|
+
|
73
|
+
it "must have a value on :save if there's no default" do
|
74
|
+
create_table(User, :login => { :null => false })
|
75
|
+
User.columns.find{|column| column.name == "login"}.required_on.should == :save
|
76
|
+
end
|
77
|
+
|
78
|
+
it "must have a value on :updae if there's default" do
|
79
|
+
create_table(User, :login => { :null => false, :default => "foo" })
|
80
|
+
User.columns.find{|column| column.name == "login"}.required_on.should == :update
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
def create_table(model, columns_with_options)
|
89
|
+
migration.suppress_messages do
|
90
|
+
migration.create_table model.table_name, :force => true do |t|
|
91
|
+
columns_with_options.each_pair do |column, options|
|
92
|
+
t.send :string, column, options
|
93
|
+
end
|
94
|
+
end
|
95
|
+
model.reset_column_information
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
data/spec/migration_spec.rb
CHANGED
@@ -46,6 +46,15 @@ describe ActiveRecord::Migration do
|
|
46
46
|
@model.should have_index.on(:state)
|
47
47
|
end
|
48
48
|
|
49
|
+
it "should create a unique index if specified on column" do
|
50
|
+
create_table(@model, :state => { :index => {:unique => true} })
|
51
|
+
@model.should have_unique_index.on(:state)
|
52
|
+
end
|
53
|
+
it "should create a unique index if specified on column using shorthand" do
|
54
|
+
create_table(@model, :state => { :index => :unique })
|
55
|
+
@model.should have_unique_index.on(:state)
|
56
|
+
end
|
57
|
+
|
49
58
|
it "should create an index if specified explicitly" do
|
50
59
|
create_table_opts(@model, {}, {:state => {}}, {:state => {}})
|
51
60
|
@model.should have_index.on(:state)
|
@@ -250,6 +259,12 @@ describe ActiveRecord::Migration do
|
|
250
259
|
end
|
251
260
|
end
|
252
261
|
|
262
|
+
it "should create a unique index if specified by shorthand" do
|
263
|
+
add_column(:post_id, :integer, :index => :unique) do
|
264
|
+
@model.should have_unique_index.on(:post_id)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
253
268
|
it "should allow custom name for index" do
|
254
269
|
index_name = 'comments_post_id_unique_index'
|
255
270
|
add_column(:post_id, :integer, :index => { :unique => true, :name => index_name }) do
|
metadata
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: schema_plus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
4
|
+
prerelease: true
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- pre4
|
10
|
+
version: 0.1.0.pre4
|
6
11
|
platform: ruby
|
7
12
|
authors:
|
8
13
|
- Ronen Barzel
|
@@ -11,17 +16,18 @@ autorequire:
|
|
11
16
|
bindir: bin
|
12
17
|
cert_chain: []
|
13
18
|
|
14
|
-
date: 2011-07-
|
19
|
+
date: 2011-07-25 00:00:00 +02:00
|
15
20
|
default_executable:
|
16
21
|
dependencies:
|
17
22
|
- !ruby/object:Gem::Dependency
|
18
23
|
name: rails
|
19
24
|
prerelease: false
|
20
25
|
requirement: &id001 !ruby/object:Gem::Requirement
|
21
|
-
none: false
|
22
26
|
requirements:
|
23
27
|
- - ">="
|
24
28
|
- !ruby/object:Gem::Version
|
29
|
+
segments:
|
30
|
+
- 0
|
25
31
|
version: "0"
|
26
32
|
type: :runtime
|
27
33
|
version_requirements: *id001
|
@@ -29,43 +35,49 @@ dependencies:
|
|
29
35
|
name: valuable
|
30
36
|
prerelease: false
|
31
37
|
requirement: &id002 !ruby/object:Gem::Requirement
|
32
|
-
none: false
|
33
38
|
requirements:
|
34
39
|
- - ">="
|
35
40
|
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
36
43
|
version: "0"
|
37
44
|
type: :runtime
|
38
45
|
version_requirements: *id002
|
39
46
|
- !ruby/object:Gem::Dependency
|
40
|
-
name:
|
47
|
+
name: mysql2
|
41
48
|
prerelease: false
|
42
49
|
requirement: &id003 !ruby/object:Gem::Requirement
|
43
|
-
none: false
|
44
50
|
requirements:
|
45
|
-
- -
|
51
|
+
- - ">="
|
46
52
|
- !ruby/object:Gem::Version
|
47
|
-
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
version: "0"
|
48
56
|
type: :development
|
49
57
|
version_requirements: *id003
|
50
58
|
- !ruby/object:Gem::Dependency
|
51
|
-
name:
|
59
|
+
name: rake
|
52
60
|
prerelease: false
|
53
61
|
requirement: &id004 !ruby/object:Gem::Requirement
|
54
|
-
none: false
|
55
62
|
requirements:
|
56
|
-
- -
|
63
|
+
- - ~>
|
57
64
|
- !ruby/object:Gem::Version
|
58
|
-
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
- 8
|
68
|
+
- 7
|
69
|
+
version: 0.8.7
|
59
70
|
type: :development
|
60
71
|
version_requirements: *id004
|
61
72
|
- !ruby/object:Gem::Dependency
|
62
73
|
name: rspec
|
63
74
|
prerelease: false
|
64
75
|
requirement: &id005 !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
76
|
requirements:
|
67
77
|
- - ">="
|
68
78
|
- !ruby/object:Gem::Version
|
79
|
+
segments:
|
80
|
+
- 0
|
69
81
|
version: "0"
|
70
82
|
type: :development
|
71
83
|
version_requirements: *id005
|
@@ -73,10 +85,11 @@ dependencies:
|
|
73
85
|
name: pg
|
74
86
|
prerelease: false
|
75
87
|
requirement: &id006 !ruby/object:Gem::Requirement
|
76
|
-
none: false
|
77
88
|
requirements:
|
78
89
|
- - ">="
|
79
90
|
- !ruby/object:Gem::Version
|
91
|
+
segments:
|
92
|
+
- 0
|
80
93
|
version: "0"
|
81
94
|
type: :development
|
82
95
|
version_requirements: *id006
|
@@ -84,68 +97,50 @@ dependencies:
|
|
84
97
|
name: mysql
|
85
98
|
prerelease: false
|
86
99
|
requirement: &id007 !ruby/object:Gem::Requirement
|
87
|
-
none: false
|
88
100
|
requirements:
|
89
101
|
- - ">="
|
90
102
|
- !ruby/object:Gem::Version
|
103
|
+
segments:
|
104
|
+
- 0
|
91
105
|
version: "0"
|
92
106
|
type: :development
|
93
107
|
version_requirements: *id007
|
94
108
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
109
|
+
name: sqlite3
|
96
110
|
prerelease: false
|
97
111
|
requirement: &id008 !ruby/object:Gem::Requirement
|
98
|
-
none: false
|
99
112
|
requirements:
|
100
113
|
- - ">="
|
101
114
|
- !ruby/object:Gem::Version
|
115
|
+
segments:
|
116
|
+
- 0
|
102
117
|
version: "0"
|
103
118
|
type: :development
|
104
119
|
version_requirements: *id008
|
105
120
|
- !ruby/object:Gem::Dependency
|
106
|
-
name:
|
121
|
+
name: simplecov
|
107
122
|
prerelease: false
|
108
123
|
requirement: &id009 !ruby/object:Gem::Requirement
|
109
|
-
none: false
|
110
124
|
requirements:
|
111
125
|
- - ">="
|
112
126
|
- !ruby/object:Gem::Version
|
127
|
+
segments:
|
128
|
+
- 0
|
113
129
|
version: "0"
|
114
130
|
type: :development
|
115
131
|
version_requirements: *id009
|
116
132
|
- !ruby/object:Gem::Dependency
|
117
|
-
name: simplecov
|
133
|
+
name: simplecov-gem-adapter
|
118
134
|
prerelease: false
|
119
135
|
requirement: &id010 !ruby/object:Gem::Requirement
|
120
|
-
none: false
|
121
136
|
requirements:
|
122
137
|
- - ">="
|
123
138
|
- !ruby/object:Gem::Version
|
139
|
+
segments:
|
140
|
+
- 0
|
124
141
|
version: "0"
|
125
142
|
type: :development
|
126
143
|
version_requirements: *id010
|
127
|
-
- !ruby/object:Gem::Dependency
|
128
|
-
name: simplecov-gem-adapter
|
129
|
-
prerelease: false
|
130
|
-
requirement: &id011 !ruby/object:Gem::Requirement
|
131
|
-
none: false
|
132
|
-
requirements:
|
133
|
-
- - ">="
|
134
|
-
- !ruby/object:Gem::Version
|
135
|
-
version: "0"
|
136
|
-
type: :development
|
137
|
-
version_requirements: *id011
|
138
|
-
- !ruby/object:Gem::Dependency
|
139
|
-
name: ruby-debug19
|
140
|
-
prerelease: false
|
141
|
-
requirement: &id012 !ruby/object:Gem::Requirement
|
142
|
-
none: false
|
143
|
-
requirements:
|
144
|
-
- - ">="
|
145
|
-
- !ruby/object:Gem::Version
|
146
|
-
version: "0"
|
147
|
-
type: :development
|
148
|
-
version_requirements: *id012
|
149
144
|
description: "SchemaPlus is an ActiveRecord extension that provides enhanced capabilities for schema definition and querying, including: enhanced and more DRY index capabilities, support and automation for foreign key constraints, and support for views."
|
150
145
|
email:
|
151
146
|
- ronen@barzel.org
|
@@ -177,12 +172,11 @@ files:
|
|
177
172
|
- lib/schema_plus/active_record/migration.rb
|
178
173
|
- lib/schema_plus/active_record/schema.rb
|
179
174
|
- lib/schema_plus/active_record/schema_dumper.rb
|
180
|
-
- lib/schema_plus/active_record/validations.rb
|
181
175
|
- lib/schema_plus/railtie.rb
|
182
176
|
- lib/schema_plus/version.rb
|
177
|
+
- runspecs
|
183
178
|
- schema_plus.gemspec
|
184
|
-
-
|
185
|
-
- schema_plus.gemspec.rails3.1
|
179
|
+
- spec/column_spec.rb
|
186
180
|
- spec/connections/mysql/connection.rb
|
187
181
|
- spec/connections/mysql2/connection.rb
|
188
182
|
- spec/connections/postgresql/connection.rb
|
@@ -207,7 +201,6 @@ files:
|
|
207
201
|
- spec/support/matchers/have_index.rb
|
208
202
|
- spec/support/matchers/reference.rb
|
209
203
|
- spec/support/reference.rb
|
210
|
-
- spec/validations_spec.rb
|
211
204
|
- spec/views_spec.rb
|
212
205
|
has_rdoc: true
|
213
206
|
homepage: https://github.com/ronen/schema_plus
|
@@ -219,48 +212,27 @@ rdoc_options: []
|
|
219
212
|
require_paths:
|
220
213
|
- lib
|
221
214
|
required_ruby_version: !ruby/object:Gem::Requirement
|
222
|
-
none: false
|
223
215
|
requirements:
|
224
216
|
- - ">="
|
225
217
|
- !ruby/object:Gem::Version
|
218
|
+
segments:
|
219
|
+
- 0
|
226
220
|
version: "0"
|
227
221
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
228
|
-
none: false
|
229
222
|
requirements:
|
230
223
|
- - ">"
|
231
224
|
- !ruby/object:Gem::Version
|
225
|
+
segments:
|
226
|
+
- 1
|
227
|
+
- 3
|
228
|
+
- 1
|
232
229
|
version: 1.3.1
|
233
230
|
requirements: []
|
234
231
|
|
235
232
|
rubyforge_project: schema_plus
|
236
|
-
rubygems_version: 1.6
|
233
|
+
rubygems_version: 1.3.6
|
237
234
|
signing_key:
|
238
235
|
specification_version: 3
|
239
236
|
summary: Enhances ActiveRecord schema mechanism, including more DRY index creation and support for foreign key constraints and views.
|
240
|
-
test_files:
|
241
|
-
|
242
|
-
- spec/connections/mysql2/connection.rb
|
243
|
-
- spec/connections/postgresql/connection.rb
|
244
|
-
- spec/connections/sqlite3/connection.rb
|
245
|
-
- spec/foreign_key_definition_spec.rb
|
246
|
-
- spec/foreign_key_spec.rb
|
247
|
-
- spec/index_definition_spec.rb
|
248
|
-
- spec/index_spec.rb
|
249
|
-
- spec/migration_spec.rb
|
250
|
-
- spec/models/comment.rb
|
251
|
-
- spec/models/post.rb
|
252
|
-
- spec/models/user.rb
|
253
|
-
- spec/references_spec.rb
|
254
|
-
- spec/schema/auto_schema.rb
|
255
|
-
- spec/schema/core_schema.rb
|
256
|
-
- spec/schema_dumper_spec.rb
|
257
|
-
- spec/schema_spec.rb
|
258
|
-
- spec/spec_helper.rb
|
259
|
-
- spec/support/extensions/active_model.rb
|
260
|
-
- spec/support/helpers.rb
|
261
|
-
- spec/support/matchers/automatic_foreign_key_matchers.rb
|
262
|
-
- spec/support/matchers/have_index.rb
|
263
|
-
- spec/support/matchers/reference.rb
|
264
|
-
- spec/support/reference.rb
|
265
|
-
- spec/validations_spec.rb
|
266
|
-
- spec/views_spec.rb
|
237
|
+
test_files: []
|
238
|
+
|
@@ -1,139 +0,0 @@
|
|
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
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "schema_plus/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = "schema_plus"
|
7
|
-
s.version = SchemaPlus::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_plus"
|
12
|
-
s.summary = "Enhances ActiveRecord schema mechanism, including more DRY index creation and support for foreign key constraints and views."
|
13
|
-
s.description = "SchemaPlus is an ActiveRecord extension that provides enhanced capabilities for schema definition and querying, including: enhanced and more DRY index capabilities, support and automation for foreign key constraints, and support for views."
|
14
|
-
|
15
|
-
s.rubyforge_project = "schema_plus"
|
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("rails")
|
23
|
-
s.add_dependency("valuable")
|
24
|
-
|
25
|
-
s.add_development_dependency("rake", "~> 0.8.7")
|
26
|
-
s.add_development_dependency("rails", "~> 3.0")
|
27
|
-
s.add_development_dependency("rspec")
|
28
|
-
s.add_development_dependency("pg")
|
29
|
-
s.add_development_dependency("mysql")
|
30
|
-
s.add_development_dependency("mysql2", "0.2.6")
|
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
|
-
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "schema_plus/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = "schema_plus"
|
7
|
-
s.version = SchemaPlus::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_plus"
|
12
|
-
s.summary = "Provides ActiveRecord support for foreign keys, database defined validations and associations."
|
13
|
-
s.description = "SchemaPlus is an ActiveRecord extension that provides support for defining foreign keys and indexes in database migrations and schemas, as well as for defining model validations and associations based on the database."
|
14
|
-
|
15
|
-
s.rubyforge_project = "schema_plus"
|
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("rails")
|
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
|
-
|
data/spec/validations_spec.rb
DELETED
@@ -1,292 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
describe "Validations" do
|
4
|
-
|
5
|
-
before(:all) do
|
6
|
-
define_schema
|
7
|
-
end
|
8
|
-
|
9
|
-
after(:each) do
|
10
|
-
remove_all_models
|
11
|
-
end
|
12
|
-
|
13
|
-
context "auto-created" do
|
14
|
-
before(:each) do
|
15
|
-
with_auto_validations do
|
16
|
-
class Article < ActiveRecord::Base ; end
|
17
|
-
|
18
|
-
class Review < ActiveRecord::Base
|
19
|
-
belongs_to :article
|
20
|
-
belongs_to :news_article, :class_name => 'Article', :foreign_key => :article_id
|
21
|
-
schema_plus :validations => { :except => :content }
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should be valid with valid attributes" do
|
27
|
-
Article.new(valid_attributes).should be_valid
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should validate content presence" do
|
31
|
-
post = Article.new.should have(1).error_on(:content)
|
32
|
-
end
|
33
|
-
|
34
|
-
it "should check title length" do
|
35
|
-
Article.new(:title => 'a' * 100).should have(1).error_on(:title)
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should validate state numericality" do
|
39
|
-
Article.new(:state => 'unknown').should have(1).error_on(:state)
|
40
|
-
end
|
41
|
-
|
42
|
-
it "should validate if state is integer" do
|
43
|
-
Article.new(:state => 1.23).should have(1).error_on(:state)
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should validate average_mark numericality" do
|
47
|
-
Article.new(:average_mark => "high").should have(1).error_on(:average_mark)
|
48
|
-
end
|
49
|
-
|
50
|
-
it "should validate boolean fields" do
|
51
|
-
Article.new(:active => nil).should have(1).error_on(:active)
|
52
|
-
end
|
53
|
-
|
54
|
-
it "should validate title uniqueness" do
|
55
|
-
article1 = Article.create(valid_attributes)
|
56
|
-
article2 = Article.new(:title => valid_attributes[:title])
|
57
|
-
article2.should have(1).error_on(:title)
|
58
|
-
article1.destroy
|
59
|
-
end
|
60
|
-
|
61
|
-
it "should validate state uniqueness in scope of 'active' value" do
|
62
|
-
article1 = Article.create(valid_attributes)
|
63
|
-
article2 = Article.new(valid_attributes.merge(:title => 'SchemaPlus 2.0 released'))
|
64
|
-
article2.should_not be_valid
|
65
|
-
article2.toggle(:active)
|
66
|
-
article2.should be_valid
|
67
|
-
article1.destroy
|
68
|
-
end
|
69
|
-
|
70
|
-
it "should validate presence of belongs_to association" do
|
71
|
-
review = Review.new
|
72
|
-
review.should have(1).error_on(:article)
|
73
|
-
end
|
74
|
-
|
75
|
-
it "should validate uniqueness of belongs_to association" do
|
76
|
-
article = Article.create(valid_attributes)
|
77
|
-
article.should be_valid
|
78
|
-
review1 = Review.create(:article => article, :author => 'michal')
|
79
|
-
review1.should be_valid
|
80
|
-
review2 = Review.new(:article => article, :author => 'michal')
|
81
|
-
review2.should have_at_least(1).error_on(:article_id)
|
82
|
-
end
|
83
|
-
|
84
|
-
it "should validate associations with unmatched column and name" do
|
85
|
-
Review.new.should have(1).error_on(:news_article)
|
86
|
-
end
|
87
|
-
|
88
|
-
def valid_attributes
|
89
|
-
{
|
90
|
-
:title => 'SchemaPlus released!',
|
91
|
-
:content => "Database matters. Get full use of it but don't write unecessary code. Get SchemaPlus!",
|
92
|
-
:state => 3,
|
93
|
-
:average_mark => 9.78,
|
94
|
-
:active => true
|
95
|
-
}
|
96
|
-
end
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
context "auto-created but changed" do
|
101
|
-
before(:each) do
|
102
|
-
with_auto_validations do
|
103
|
-
class Article < ActiveRecord::Base ; end
|
104
|
-
class Review < ActiveRecord::Base
|
105
|
-
belongs_to :article
|
106
|
-
belongs_to :news_article, :class_name => 'Article', :foreign_key => :article_id
|
107
|
-
end
|
108
|
-
end
|
109
|
-
too_big_content = 'a' * 1000
|
110
|
-
@review = Review.new(:content => too_big_content)
|
111
|
-
end
|
112
|
-
|
113
|
-
it "would normally have an error" do
|
114
|
-
@review.should have(1).error_on(:content)
|
115
|
-
@review.should have(1).error_on(:author)
|
116
|
-
end
|
117
|
-
|
118
|
-
it "shouldn't validate fields passed to :except option" do
|
119
|
-
Review.schema_plus :validations => { :except => :content }
|
120
|
-
@review.should have(:no).errors_on(:content)
|
121
|
-
@review.should have(1).error_on(:author)
|
122
|
-
end
|
123
|
-
|
124
|
-
it "shouldn't validate types passed to :except_type option using full validation" do
|
125
|
-
Review.schema_plus :validations => { :except_type => :validates_length_of }
|
126
|
-
@review.should have(:no).errors_on(:content)
|
127
|
-
@review.should have(1).error_on(:author)
|
128
|
-
end
|
129
|
-
|
130
|
-
it "shouldn't validate types passed to :except_type option using shorthand" do
|
131
|
-
Review.schema_plus :validations => { :except_type => :length }
|
132
|
-
@review.should have(:no).errors_on(:content)
|
133
|
-
@review.should have(1).error_on(:author)
|
134
|
-
end
|
135
|
-
|
136
|
-
it "should only validate type passed to :only_type option" do
|
137
|
-
Review.schema_plus :validations => { :only_type => :length }
|
138
|
-
@review.should have(1).error_on(:content)
|
139
|
-
@review.should have(:no).errors_on(:author)
|
140
|
-
end
|
141
|
-
|
142
|
-
|
143
|
-
it "shouldn't create validations if locally disabled" do
|
144
|
-
Review.schema_plus :validations => { :auto_create => false }
|
145
|
-
@review.should have(:no).errors_on(:content)
|
146
|
-
@review.should have(:no).error_on(:author)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
context "auto-created disabled" do
|
151
|
-
around(:each) do |example|
|
152
|
-
with_auto_validations(false, &example)
|
153
|
-
end
|
154
|
-
|
155
|
-
before(:each) do
|
156
|
-
class Article < ActiveRecord::Base ; end
|
157
|
-
|
158
|
-
class Review < ActiveRecord::Base
|
159
|
-
belongs_to :article
|
160
|
-
belongs_to :news_article, :class_name => 'Article', :foreign_key => :article_id
|
161
|
-
end
|
162
|
-
too_big_content = 'a' * 1000
|
163
|
-
@review = Review.new(:content => too_big_content)
|
164
|
-
end
|
165
|
-
|
166
|
-
it "should not create validation" do
|
167
|
-
@review.should have(:no).errors_on(:content)
|
168
|
-
end
|
169
|
-
|
170
|
-
it "should create validation if locally enabled" do
|
171
|
-
Review.schema_plus :validations => { :auto_create => true }
|
172
|
-
@review.should have(1).error_on(:content)
|
173
|
-
end
|
174
|
-
|
175
|
-
end
|
176
|
-
|
177
|
-
context "manually invoked" do
|
178
|
-
before(:each) do
|
179
|
-
class Article < ActiveRecord::Base ; end
|
180
|
-
Article.schema_plus :validations => { :only => [:title, :state] }
|
181
|
-
|
182
|
-
class Review < ActiveRecord::Base
|
183
|
-
belongs_to :dummy_association
|
184
|
-
schema_plus :validations => { :except => :content }
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
it "should validate fields passed to :only option" do
|
189
|
-
too_big_title = 'a' * 100
|
190
|
-
wrong_state = 'unknown'
|
191
|
-
article = Article.new(:title => too_big_title, :state => wrong_state)
|
192
|
-
article.should have(1).error_on(:title)
|
193
|
-
article.should have(1).error_on(:state)
|
194
|
-
end
|
195
|
-
|
196
|
-
it "shouldn't validate skipped fields" do
|
197
|
-
article = Article.new
|
198
|
-
article.should have(:no).errors_on(:content)
|
199
|
-
article.should have(:no).errors_on(:average_mark)
|
200
|
-
end
|
201
|
-
|
202
|
-
it "shouldn't validate association on unexisting column" do
|
203
|
-
Review.new.should have(:no).errors_on(:dummy_association)
|
204
|
-
end
|
205
|
-
|
206
|
-
it "shouldn't validate fields passed to :except option" do
|
207
|
-
Review.new.should have(:no).errors_on(:content)
|
208
|
-
end
|
209
|
-
|
210
|
-
it "should validate all fields but passed to :except option" do
|
211
|
-
Review.new.should have(1).error_on(:author)
|
212
|
-
end
|
213
|
-
|
214
|
-
end
|
215
|
-
|
216
|
-
context "manually invoked" do
|
217
|
-
before(:each) do
|
218
|
-
class Review < ActiveRecord::Base
|
219
|
-
belongs_to :article
|
220
|
-
end
|
221
|
-
@columns = Review.content_columns.dup
|
222
|
-
Review.schema_plus :validations => { :only => [:title] }
|
223
|
-
end
|
224
|
-
|
225
|
-
it "shouldn't validate associations not included in :only option" do
|
226
|
-
Review.new.should have(:no).errors_on(:article)
|
227
|
-
end
|
228
|
-
|
229
|
-
it "shouldn't change content columns of the model" do
|
230
|
-
@columns.should == Review.content_columns
|
231
|
-
end
|
232
|
-
|
233
|
-
end
|
234
|
-
|
235
|
-
context "when used with STI" do
|
236
|
-
around(:each) { |example| with_auto_validations(&example) }
|
237
|
-
|
238
|
-
it "should set validations on base class" do
|
239
|
-
class Review < ActiveRecord::Base ; end
|
240
|
-
class PremiumReview < Review ; end
|
241
|
-
PremiumReview.new
|
242
|
-
Review.new.should have(1).error_on(:author)
|
243
|
-
end
|
244
|
-
|
245
|
-
it "shouldn't create doubled validations" do
|
246
|
-
class Review < ActiveRecord::Base ; end
|
247
|
-
Review.new
|
248
|
-
class PremiumReview < Review ; end
|
249
|
-
PremiumReview.new.should have(1).error_on(:author)
|
250
|
-
end
|
251
|
-
|
252
|
-
end
|
253
|
-
|
254
|
-
protected
|
255
|
-
def with_auto_validations(value = true)
|
256
|
-
old_value = SchemaPlus.config.validations.auto_create
|
257
|
-
begin
|
258
|
-
SchemaPlus.config.validations.auto_create = value
|
259
|
-
yield
|
260
|
-
ensure
|
261
|
-
SchemaPlus.config.validations.auto_create = old_value
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
def define_schema
|
266
|
-
ActiveRecord::Migration.suppress_messages do
|
267
|
-
ActiveRecord::Schema.define do
|
268
|
-
connection.tables.each do |table| drop_table table end
|
269
|
-
|
270
|
-
create_table :articles, :force => true do |t|
|
271
|
-
t.string :title, :limit => 50
|
272
|
-
t.text :content, :null => false
|
273
|
-
t.integer :state
|
274
|
-
t.float :average_mark, :null => false
|
275
|
-
t.boolean :active, :null => false
|
276
|
-
end
|
277
|
-
add_index :articles, :title, :unique => true
|
278
|
-
add_index :articles, [:state, :active], :unique => true
|
279
|
-
|
280
|
-
create_table :reviews, :force => true do |t|
|
281
|
-
t.integer :article_id, :null => false
|
282
|
-
t.string :author, :null => false
|
283
|
-
t.string :content, :limit => 200
|
284
|
-
t.string :type
|
285
|
-
end
|
286
|
-
add_index :reviews, :article_id, :unique => true
|
287
|
-
|
288
|
-
end
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
end
|