activerecord-oracle_enhanced-adapter 1.5.5 → 1.5.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +25 -0
- data/README.md +5 -4
- data/VERSION +1 -1
- data/activerecord-oracle_enhanced-adapter.gemspec +3 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +28 -274
- data/lib/active_record/connection_adapters/oracle_enhanced_database_statements.rb +262 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_database_tasks.rb +7 -6
- data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +0 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +9 -7
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +2 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +4 -5
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +3 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +0 -8
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +64 -25
- data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +6 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +12 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +25 -0
- metadata +4 -3
@@ -29,7 +29,7 @@ describe "OracleEnhancedAdapter date type detection based on column names" do
|
|
29
29
|
INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
|
30
30
|
SQL
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
after(:all) do
|
34
34
|
@conn.execute "DROP TABLE test_employees"
|
35
35
|
@conn.execute "DROP SEQUENCE test_employees_seq"
|
@@ -92,7 +92,7 @@ describe "OracleEnhancedAdapter date type detection based on column names" do
|
|
92
92
|
self.primary_key = "employee_id"
|
93
93
|
end
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
def create_test_employee(params={})
|
97
97
|
@today = params[:today] || Date.new(2008,8,19)
|
98
98
|
@now = params[:now] || Time.local(2008,8,19,17,03,59)
|
@@ -317,7 +317,7 @@ describe "OracleEnhancedAdapter integer type detection based on column names" do
|
|
317
317
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans = true
|
318
318
|
ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
|
319
319
|
end
|
320
|
-
|
320
|
+
|
321
321
|
def create_employee2
|
322
322
|
@employee2 = Test2Employee.create(
|
323
323
|
:first_name => "First",
|
@@ -328,7 +328,7 @@ describe "OracleEnhancedAdapter integer type detection based on column names" do
|
|
328
328
|
)
|
329
329
|
@employee2.reload
|
330
330
|
end
|
331
|
-
|
331
|
+
|
332
332
|
it "should return BigDecimal value from NUMBER column if emulate_integers_by_column_name is false" do
|
333
333
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = false
|
334
334
|
create_employee2
|
@@ -413,7 +413,7 @@ describe "OracleEnhancedAdapter boolean type detection based on string column ty
|
|
413
413
|
INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
|
414
414
|
SQL
|
415
415
|
end
|
416
|
-
|
416
|
+
|
417
417
|
after(:all) do
|
418
418
|
@conn.execute "DROP TABLE test3_employees"
|
419
419
|
@conn.execute "DROP SEQUENCE test3_employees_seq"
|
@@ -437,7 +437,7 @@ describe "OracleEnhancedAdapter boolean type detection based on string column ty
|
|
437
437
|
column.type.should == :boolean
|
438
438
|
end
|
439
439
|
end
|
440
|
-
|
440
|
+
|
441
441
|
it "should set VARCHAR2 column type as string if column name does not contain 'flag' or 'yn' and emulate_booleans_from_strings is true" do
|
442
442
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
|
443
443
|
columns = @conn.columns('test3_employees')
|
@@ -446,7 +446,7 @@ describe "OracleEnhancedAdapter boolean type detection based on string column ty
|
|
446
446
|
column.type.should == :string
|
447
447
|
end
|
448
448
|
end
|
449
|
-
|
449
|
+
|
450
450
|
it "should return string value from VARCHAR2 boolean column if emulate_booleans_from_strings is false" do
|
451
451
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
|
452
452
|
columns = @conn.columns('test3_employees')
|
@@ -455,7 +455,7 @@ describe "OracleEnhancedAdapter boolean type detection based on string column ty
|
|
455
455
|
column.type_cast("Y").class.should == String
|
456
456
|
end
|
457
457
|
end
|
458
|
-
|
458
|
+
|
459
459
|
it "should return boolean value from VARCHAR2 boolean column if emulate_booleans_from_strings is true" do
|
460
460
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
|
461
461
|
columns = @conn.columns('test3_employees')
|
@@ -484,20 +484,20 @@ describe "OracleEnhancedAdapter boolean type detection based on string column ty
|
|
484
484
|
columns.detect{|c| c.name == 'has_phone'}.default.should be_true
|
485
485
|
columns.detect{|c| c.name == 'manager_yn'}.default.should be_false
|
486
486
|
end
|
487
|
-
|
487
|
+
|
488
488
|
describe "/ VARCHAR2 boolean values from ActiveRecord model" do
|
489
489
|
before(:each) do
|
490
490
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
|
491
491
|
class ::Test3Employee < ActiveRecord::Base
|
492
492
|
end
|
493
493
|
end
|
494
|
-
|
494
|
+
|
495
495
|
after(:each) do
|
496
496
|
Object.send(:remove_const, "Test3Employee")
|
497
497
|
@conn.clear_types_for_columns
|
498
498
|
ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
|
499
499
|
end
|
500
|
-
|
500
|
+
|
501
501
|
def create_employee3(params={})
|
502
502
|
@employee3 = Test3Employee.create(
|
503
503
|
{
|
@@ -511,7 +511,7 @@ describe "OracleEnhancedAdapter boolean type detection based on string column ty
|
|
511
511
|
)
|
512
512
|
@employee3.reload
|
513
513
|
end
|
514
|
-
|
514
|
+
|
515
515
|
it "should return String value from VARCHAR2 boolean column if emulate_booleans_from_strings is false" do
|
516
516
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
|
517
517
|
create_employee3
|
@@ -519,7 +519,7 @@ describe "OracleEnhancedAdapter boolean type detection based on string column ty
|
|
519
519
|
@employee3.send(col.to_sym).class.should == String
|
520
520
|
end
|
521
521
|
end
|
522
|
-
|
522
|
+
|
523
523
|
it "should return boolean value from VARCHAR2 boolean column if emulate_booleans_from_strings is true" do
|
524
524
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
|
525
525
|
create_employee3
|
@@ -532,7 +532,7 @@ describe "OracleEnhancedAdapter boolean type detection based on string column ty
|
|
532
532
|
@employee3.send((col+"_before_type_cast").to_sym).should == "N"
|
533
533
|
end
|
534
534
|
end
|
535
|
-
|
535
|
+
|
536
536
|
it "should return string value from VARCHAR2 column if it is not boolean column and emulate_booleans_from_strings is true" do
|
537
537
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
|
538
538
|
create_employee3
|
@@ -594,7 +594,7 @@ describe "OracleEnhancedAdapter timestamp with timezone support" do
|
|
594
594
|
INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
|
595
595
|
SQL
|
596
596
|
end
|
597
|
-
|
597
|
+
|
598
598
|
after(:all) do
|
599
599
|
@conn.execute "DROP TABLE test_employees"
|
600
600
|
@conn.execute "DROP SEQUENCE test_employees_seq"
|
@@ -680,7 +680,7 @@ describe "OracleEnhancedAdapter date and timestamp with different NLS date forma
|
|
680
680
|
# @conn.execute %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'}
|
681
681
|
@conn.execute %q{alter session set nls_timestamp_format = 'DD-MON-YYYY HH24:MI:SS'}
|
682
682
|
end
|
683
|
-
|
683
|
+
|
684
684
|
after(:all) do
|
685
685
|
@conn.execute "DROP TABLE test_employees"
|
686
686
|
@conn.execute "DROP SEQUENCE test_employees_seq"
|
@@ -697,10 +697,10 @@ describe "OracleEnhancedAdapter date and timestamp with different NLS date forma
|
|
697
697
|
end
|
698
698
|
|
699
699
|
after(:each) do
|
700
|
-
Object.send(:remove_const, "TestEmployee")
|
700
|
+
Object.send(:remove_const, "TestEmployee")
|
701
701
|
ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
|
702
702
|
end
|
703
|
-
|
703
|
+
|
704
704
|
def create_test_employee
|
705
705
|
@employee = TestEmployee.create(
|
706
706
|
:first_name => "First",
|
@@ -709,7 +709,7 @@ describe "OracleEnhancedAdapter date and timestamp with different NLS date forma
|
|
709
709
|
:created_at => @now,
|
710
710
|
:created_at_ts => @now
|
711
711
|
)
|
712
|
-
@employee.reload
|
712
|
+
@employee.reload
|
713
713
|
end
|
714
714
|
|
715
715
|
it "should return Time value from DATE column if emulate_dates_by_column_name is false" do
|
@@ -789,7 +789,7 @@ describe "OracleEnhancedAdapter assign string to :date and :datetime columns" do
|
|
789
789
|
@nls_with_tz_time_format = "%d.%m.%Y %H:%M:%S%Z"
|
790
790
|
@now_with_tz = Time.parse @now_nls_with_tz
|
791
791
|
end
|
792
|
-
|
792
|
+
|
793
793
|
after(:all) do
|
794
794
|
Object.send(:remove_const, "TestEmployee")
|
795
795
|
@conn.execute "DROP TABLE test_employees"
|
@@ -800,7 +800,7 @@ describe "OracleEnhancedAdapter assign string to :date and :datetime columns" do
|
|
800
800
|
before(:each) do
|
801
801
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
802
802
|
end
|
803
|
-
|
803
|
+
|
804
804
|
it "should assign ISO string to date column" do
|
805
805
|
@employee = TestEmployee.create(
|
806
806
|
:first_name => "First",
|
@@ -937,6 +937,19 @@ describe "OracleEnhancedAdapter handling of CLOB columns" do
|
|
937
937
|
CREATE SEQUENCE test2_employees_seq MINVALUE 1
|
938
938
|
INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
|
939
939
|
SQL
|
940
|
+
@conn.execute <<-SQL
|
941
|
+
CREATE TABLE test_serialize_employees (
|
942
|
+
id NUMBER(6,0) PRIMARY KEY,
|
943
|
+
first_name VARCHAR2(20),
|
944
|
+
last_name VARCHAR2(25)
|
945
|
+
)
|
946
|
+
SQL
|
947
|
+
@conn.execute <<-SQL
|
948
|
+
CREATE SEQUENCE test_serialize_employees_seq MINVALUE 1
|
949
|
+
INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
|
950
|
+
SQL
|
951
|
+
ActiveRecord::Base.connection.add_column(:test_serialize_employees, :comments, :text)
|
952
|
+
|
940
953
|
@char_data = (0..127).to_a.pack("C*") * 800
|
941
954
|
@char_data2 = ((1..127).to_a.pack("C*") + "\0") * 800
|
942
955
|
|
@@ -948,6 +961,10 @@ describe "OracleEnhancedAdapter handling of CLOB columns" do
|
|
948
961
|
self.table_name = "test_employees"
|
949
962
|
attr_readonly :comments
|
950
963
|
end
|
964
|
+
class ::TestSerializeEmployee < ActiveRecord::Base
|
965
|
+
serialize :comments
|
966
|
+
attr_readonly :comments
|
967
|
+
end
|
951
968
|
end
|
952
969
|
|
953
970
|
after(:all) do
|
@@ -955,9 +972,12 @@ describe "OracleEnhancedAdapter handling of CLOB columns" do
|
|
955
972
|
@conn.execute "DROP SEQUENCE test_employees_seq"
|
956
973
|
@conn.execute "DROP TABLE test2_employees"
|
957
974
|
@conn.execute "DROP SEQUENCE test2_employees_seq"
|
975
|
+
@conn.execute "DROP TABLE test_serialize_employees"
|
976
|
+
@conn.execute "DROP SEQUENCE test_serialize_employees_seq"
|
958
977
|
Object.send(:remove_const, "TestEmployee")
|
959
978
|
Object.send(:remove_const, "Test2Employee")
|
960
979
|
Object.send(:remove_const, "TestEmployeeReadOnlyClob")
|
980
|
+
Object.send(:remove_const, "TestSerializeEmployee")
|
961
981
|
ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
|
962
982
|
end
|
963
983
|
|
@@ -967,6 +987,8 @@ describe "OracleEnhancedAdapter handling of CLOB columns" do
|
|
967
987
|
:last_name => "Last"
|
968
988
|
)
|
969
989
|
@employee.should be_valid
|
990
|
+
@employee.reload
|
991
|
+
@employee.comments.should be_nil
|
970
992
|
end
|
971
993
|
|
972
994
|
it "should accept Symbol value for CLOB column" do
|
@@ -990,6 +1012,23 @@ describe "OracleEnhancedAdapter handling of CLOB columns" do
|
|
990
1012
|
@employee.comments.should == 'initial'
|
991
1013
|
end
|
992
1014
|
|
1015
|
+
it "should work for serialized readonly CLOB columns", serialized: true do
|
1016
|
+
@employee = TestSerializeEmployee.new(
|
1017
|
+
:first_name => "First",
|
1018
|
+
:comments => nil
|
1019
|
+
)
|
1020
|
+
@employee.comments.should be_nil
|
1021
|
+
@employee.save.should == true
|
1022
|
+
@employee.should be_valid
|
1023
|
+
@employee.reload
|
1024
|
+
@employee.comments.should be_nil
|
1025
|
+
@employee.comments = {}
|
1026
|
+
@employee.save.should == true
|
1027
|
+
@employee.reload
|
1028
|
+
#should not set readonly
|
1029
|
+
@employee.comments.should be_nil
|
1030
|
+
end
|
1031
|
+
|
993
1032
|
|
994
1033
|
it "should create record with CLOB data" do
|
995
1034
|
@employee = TestEmployee.create!(
|
@@ -1112,7 +1151,7 @@ describe "OracleEnhancedAdapter handling of BLOB columns" do
|
|
1112
1151
|
@binary_data = "\0\1\2\3\4\5\6\7\8\9"*10000
|
1113
1152
|
@binary_data2 = "\1\2\3\4\5\6\7\8\9\0"*10000
|
1114
1153
|
end
|
1115
|
-
|
1154
|
+
|
1116
1155
|
after(:all) do
|
1117
1156
|
@conn.execute "DROP TABLE test_employees"
|
1118
1157
|
@conn.execute "DROP SEQUENCE test_employees_seq"
|
@@ -1123,12 +1162,12 @@ describe "OracleEnhancedAdapter handling of BLOB columns" do
|
|
1123
1162
|
self.primary_key = "employee_id"
|
1124
1163
|
end
|
1125
1164
|
end
|
1126
|
-
|
1165
|
+
|
1127
1166
|
after(:each) do
|
1128
1167
|
Object.send(:remove_const, "TestEmployee")
|
1129
1168
|
ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
|
1130
1169
|
end
|
1131
|
-
|
1170
|
+
|
1132
1171
|
it "should create record with BLOB data" do
|
1133
1172
|
@employee = TestEmployee.create!(
|
1134
1173
|
:first_name => "First",
|
@@ -1138,7 +1177,7 @@ describe "OracleEnhancedAdapter handling of BLOB columns" do
|
|
1138
1177
|
@employee.reload
|
1139
1178
|
@employee.binary_data.should == @binary_data
|
1140
1179
|
end
|
1141
|
-
|
1180
|
+
|
1142
1181
|
it "should update record with BLOB data" do
|
1143
1182
|
@employee = TestEmployee.create!(
|
1144
1183
|
:first_name => "First",
|
@@ -56,13 +56,17 @@ describe "Oracle Enhanced adapter database tasks" do
|
|
56
56
|
|
57
57
|
describe "structure" do
|
58
58
|
let(:temp_file) { Tempfile.new(["oracle_enhanced", ".sql"]).path }
|
59
|
-
before
|
59
|
+
before do
|
60
|
+
ActiveRecord::SchemaMigration.create_table
|
61
|
+
ActiveRecord::Base.connection.execute "INSERT INTO schema_migrations (version) VALUES ('20150101010000')"
|
62
|
+
end
|
60
63
|
|
61
64
|
describe "structure_dump" do
|
62
65
|
before { ActiveRecord::Tasks::DatabaseTasks.structure_dump(config, temp_file) }
|
63
|
-
it "dumps the database structure to a file" do
|
66
|
+
it "dumps the database structure to a file without the schema information" do
|
64
67
|
contents = File.read(temp_file)
|
65
68
|
contents.should include('CREATE TABLE "TEST_POSTS"')
|
69
|
+
contents.should_not include('INSERT INTO schema_migrations')
|
66
70
|
end
|
67
71
|
end
|
68
72
|
|
@@ -385,6 +385,18 @@ describe "OracleEnhancedAdapter schema definition" do
|
|
385
385
|
|
386
386
|
end
|
387
387
|
|
388
|
+
describe "drop tables" do
|
389
|
+
before(:each) do
|
390
|
+
@conn = ActiveRecord::Base.connection
|
391
|
+
end
|
392
|
+
|
393
|
+
it "should drop table with :if_exists option no raise error" do
|
394
|
+
lambda do
|
395
|
+
@conn.drop_table("nonexistent_table", if_exists: true)
|
396
|
+
end.should_not raise_error
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
388
400
|
describe "rename tables and sequences" do
|
389
401
|
before(:each) do
|
390
402
|
@conn = ActiveRecord::Base.connection
|
@@ -161,6 +161,18 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
161
161
|
dump.should =~ /\"?ID_PLUS\"? NUMBER GENERATED ALWAYS AS \(ID\+2\) VIRTUAL/
|
162
162
|
end
|
163
163
|
|
164
|
+
it "should dump RAW virtual columns" do
|
165
|
+
@conn.execute <<-SQL
|
166
|
+
CREATE TABLE bars (
|
167
|
+
id NUMBER(38,0) NOT NULL,
|
168
|
+
super RAW(255) GENERATED ALWAYS AS \( HEXTORAW\(ID\) \) VIRTUAL,
|
169
|
+
PRIMARY KEY (ID)
|
170
|
+
)
|
171
|
+
SQL
|
172
|
+
dump = ActiveRecord::Base.connection.structure_dump
|
173
|
+
dump.should =~ /CREATE TABLE \"BARS\" \(\n\"ID\" NUMBER\(38,0\) NOT NULL,\n \"SUPER\" RAW\(255\) GENERATED ALWAYS AS \(HEXTORAW\(TO_CHAR\(ID\)\)\) VIRTUAL/
|
174
|
+
end
|
175
|
+
|
164
176
|
it "should dump unique keys" do
|
165
177
|
@conn.execute <<-SQL
|
166
178
|
ALTER TABLE test_posts
|
@@ -199,6 +211,19 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
199
211
|
dump.should =~ /CREATE INDEX "?IX_TEST_POSTS_FOO_FOO_ID\"? ON "?TEST_POSTS"? \("?FOO"?, "?FOO_ID"?\)/i
|
200
212
|
dump.should =~ /CREATE INDEX "?IX_TEST_POSTS_FUNCTION\"? ON "?TEST_POSTS"? \(TO_CHAR\(LENGTH\("?FOO"?\)\)\|\|"?FOO"?\)/i
|
201
213
|
end
|
214
|
+
|
215
|
+
it "should dump RAW columns" do
|
216
|
+
@conn.execute <<-SQL
|
217
|
+
CREATE TABLE bars (
|
218
|
+
id NUMBER(38,0) NOT NULL,
|
219
|
+
super RAW(255),
|
220
|
+
PRIMARY KEY (ID)
|
221
|
+
)
|
222
|
+
SQL
|
223
|
+
dump = ActiveRecord::Base.connection.structure_dump
|
224
|
+
dump.should =~ /CREATE TABLE \"BARS\" \(\n\"ID\" NUMBER\(38,0\) NOT NULL,\n \"SUPER\" RAW\(255\)/
|
225
|
+
end
|
226
|
+
|
202
227
|
end
|
203
228
|
describe "temporary tables" do
|
204
229
|
after(:all) do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-oracle_enhanced-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Raimonds Simanovskis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jeweler
|
@@ -217,6 +217,7 @@ files:
|
|
217
217
|
- lib/active_record/connection_adapters/oracle_enhanced_connection.rb
|
218
218
|
- lib/active_record/connection_adapters/oracle_enhanced_context_index.rb
|
219
219
|
- lib/active_record/connection_adapters/oracle_enhanced_cpk.rb
|
220
|
+
- lib/active_record/connection_adapters/oracle_enhanced_database_statements.rb
|
220
221
|
- lib/active_record/connection_adapters/oracle_enhanced_database_tasks.rb
|
221
222
|
- lib/active_record/connection_adapters/oracle_enhanced_dirty.rb
|
222
223
|
- lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb
|
@@ -264,7 +265,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
264
265
|
version: '0'
|
265
266
|
requirements: []
|
266
267
|
rubyforge_project:
|
267
|
-
rubygems_version: 2.
|
268
|
+
rubygems_version: 2.4.6
|
268
269
|
signing_key:
|
269
270
|
specification_version: 4
|
270
271
|
summary: Oracle enhanced adapter for ActiveRecord
|