sequel 3.21.0 → 3.31.0
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/CHANGELOG +485 -3
- data/README.rdoc +20 -6
- data/Rakefile +37 -19
- data/bin/sequel +1 -5
- data/doc/association_basics.rdoc +249 -43
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +15 -538
- data/doc/model_hooks.rdoc +72 -27
- data/doc/opening_databases.rdoc +89 -50
- data/doc/prepared_statements.rdoc +40 -13
- data/doc/reflection.rdoc +8 -2
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/doc/schema_modification.rdoc +547 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +129 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +17 -9
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +5 -7
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/do.rb +17 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +448 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/db2.rb +45 -0
- data/lib/sequel/adapters/jdbc/derby.rb +247 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +56 -29
- data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
- data/lib/sequel/adapters/jdbc/informix.rb +26 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
- data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
- data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +231 -78
- data/lib/sequel/adapters/mock.rb +335 -0
- data/lib/sequel/adapters/mysql.rb +82 -184
- data/lib/sequel/adapters/mysql2.rb +26 -25
- data/lib/sequel/adapters/odbc/db2.rb +17 -0
- data/lib/sequel/adapters/odbc/mssql.rb +1 -6
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +351 -53
- data/lib/sequel/adapters/postgres.rb +194 -33
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +321 -0
- data/lib/sequel/adapters/shared/firebird.rb +221 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +231 -106
- data/lib/sequel/adapters/shared/mysql.rb +181 -63
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +231 -41
- data/lib/sequel/adapters/shared/postgres.rb +214 -82
- data/lib/sequel/adapters/shared/progress.rb +4 -7
- data/lib/sequel/adapters/shared/sqlite.rb +201 -57
- data/lib/sequel/adapters/sqlite.rb +29 -21
- data/lib/sequel/adapters/swift/mysql.rb +12 -7
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/tinytds.rb +160 -19
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +46 -5
- data/lib/sequel/database/connecting.rb +5 -6
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +59 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +104 -19
- data/lib/sequel/database/query.rb +153 -58
- data/lib/sequel/database/schema_generator.rb +17 -7
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +231 -76
- data/lib/sequel/dataset/features.rb +91 -8
- data/lib/sequel/dataset/graph.rb +38 -11
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +5 -6
- data/lib/sequel/dataset/prepared_statements.rb +48 -27
- data/lib/sequel/dataset/query.rb +236 -43
- data/lib/sequel/dataset/sql.rb +665 -253
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +1020 -337
- data/lib/sequel/model/base.rb +414 -132
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +15 -8
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +114 -7
- data/lib/sequel/plugins/many_through_many.rb +65 -7
- data/lib/sequel/plugins/prepared_statements.rb +151 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +88 -44
- data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +109 -52
- data/lib/sequel/timezones.rb +57 -38
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/mssql_spec.rb +111 -29
- data/spec/adapters/mysql_spec.rb +135 -123
- data/spec/adapters/oracle_spec.rb +49 -77
- data/spec/adapters/postgres_spec.rb +267 -78
- data/spec/adapters/spec_helper.rb +6 -5
- data/spec/adapters/sqlite_spec.rb +35 -21
- data/spec/core/connection_pool_spec.rb +71 -92
- data/spec/core/core_sql_spec.rb +21 -30
- data/spec/core/database_spec.rb +788 -512
- data/spec/core/dataset_spec.rb +1073 -1053
- data/spec/core/expression_filters_spec.rb +159 -42
- data/spec/core/mock_adapter_spec.rb +419 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +298 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/association_autoreloading_spec.rb +1 -10
- data/spec/extensions/association_dependencies_spec.rb +2 -12
- data/spec/extensions/association_pks_spec.rb +66 -32
- data/spec/extensions/caching_spec.rb +23 -50
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/hook_class_methods_spec.rb +65 -91
- data/spec/extensions/identity_map_spec.rb +114 -22
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +53 -0
- data/spec/extensions/json_serializer_spec.rb +4 -5
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +17 -39
- data/spec/extensions/many_through_many_spec.rb +283 -250
- data/spec/extensions/migration_spec.rb +35 -32
- data/spec/extensions/named_timezones_spec.rb +23 -3
- data/spec/extensions/nested_attributes_spec.rb +97 -88
- data/spec/extensions/optimistic_locking_spec.rb +9 -20
- data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
- data/spec/extensions/prepared_statements_spec.rb +53 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +1 -6
- data/spec/extensions/rcte_tree_spec.rb +41 -43
- data/spec/extensions/schema_dumper_spec.rb +5 -8
- data/spec/extensions/schema_spec.rb +13 -21
- data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
- data/spec/extensions/serialization_spec.rb +72 -43
- data/spec/extensions/sharding_spec.rb +66 -140
- data/spec/extensions/single_table_inheritance_spec.rb +18 -29
- data/spec/extensions/spec_helper.rb +13 -61
- data/spec/extensions/sql_expr_spec.rb +20 -60
- data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +4 -7
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +30 -51
- data/spec/extensions/validation_helpers_spec.rb +16 -35
- data/spec/extensions/xml_serializer_spec.rb +16 -4
- data/spec/integration/associations_test.rb +537 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +461 -65
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +304 -116
- data/spec/integration/prepared_statement_test.rb +212 -122
- data/spec/integration/schema_test.rb +161 -30
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +172 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +865 -662
- data/spec/model/base_spec.rb +275 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +677 -676
- data/spec/model/hooks_spec.rb +309 -67
- data/spec/model/model_spec.rb +222 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +381 -218
- data/spec/model/spec_helper.rb +13 -71
- data/spec/model/validations_spec.rb +11 -0
- metadata +115 -73
data/Rakefile
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
require "rake"
|
|
2
2
|
require "rake/clean"
|
|
3
|
-
require "rake/gempackagetask"
|
|
4
|
-
begin
|
|
5
|
-
require "hanna/rdoctask"
|
|
6
|
-
rescue LoadError
|
|
7
|
-
require "rake/rdoctask"
|
|
8
|
-
end
|
|
9
3
|
|
|
10
4
|
NAME = 'sequel'
|
|
11
5
|
VERS = lambda do
|
|
@@ -13,14 +7,13 @@ VERS = lambda do
|
|
|
13
7
|
Sequel.version
|
|
14
8
|
end
|
|
15
9
|
CLEAN.include ["**/.*.sw?", "sequel-*.gem", ".config", "rdoc", "coverage", "www/public/*.html", "www/public/rdoc*", '**/*.rbc']
|
|
16
|
-
RDOC_DEFAULT_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', 'Sequel: The Database Toolkit for Ruby']
|
|
17
|
-
RDOC_OPTS = RDOC_DEFAULT_OPTS + ['--main', 'README.rdoc']
|
|
18
10
|
|
|
19
11
|
# Gem Packaging and Release
|
|
20
12
|
|
|
21
13
|
desc "Packages sequel"
|
|
22
14
|
task :package=>[:clean] do |p|
|
|
23
|
-
|
|
15
|
+
load './sequel.gemspec'
|
|
16
|
+
Gem::Builder.new(SEQUEL_GEMSPEC).build
|
|
24
17
|
end
|
|
25
18
|
|
|
26
19
|
desc "Install sequel gem"
|
|
@@ -40,7 +33,20 @@ end
|
|
|
40
33
|
|
|
41
34
|
### RDoc
|
|
42
35
|
|
|
43
|
-
|
|
36
|
+
RDOC_DEFAULT_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', 'Sequel: The Database Toolkit for Ruby']
|
|
37
|
+
|
|
38
|
+
rdoc_task_class = begin
|
|
39
|
+
require "rdoc/task"
|
|
40
|
+
RDOC_DEFAULT_OPTS.concat(['-f', 'hanna'])
|
|
41
|
+
RDoc::Task
|
|
42
|
+
rescue LoadError
|
|
43
|
+
require "rake/rdoctask"
|
|
44
|
+
Rake::RDocTask
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
RDOC_OPTS = RDOC_DEFAULT_OPTS + ['--main', 'README.rdoc']
|
|
48
|
+
|
|
49
|
+
rdoc_task_class.new do |rdoc|
|
|
44
50
|
rdoc.rdoc_dir = "rdoc"
|
|
45
51
|
rdoc.options += RDOC_OPTS
|
|
46
52
|
rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/**/*.rb doc/*.rdoc doc/release_notes/*.txt"
|
|
@@ -50,25 +56,25 @@ end
|
|
|
50
56
|
|
|
51
57
|
desc "Make local version of website"
|
|
52
58
|
task :website do
|
|
53
|
-
sh %{www/make_www.rb}
|
|
59
|
+
sh %{#{FileUtils::RUBY} www/make_www.rb}
|
|
54
60
|
end
|
|
55
61
|
|
|
56
62
|
desc "Make rdoc for website"
|
|
57
63
|
task :website_rdoc=>[:website_rdoc_main, :website_rdoc_adapters, :website_rdoc_plugins]
|
|
58
64
|
|
|
59
|
-
|
|
65
|
+
rdoc_task_class.new(:website_rdoc_main) do |rdoc|
|
|
60
66
|
rdoc.rdoc_dir = "www/public/rdoc"
|
|
61
67
|
rdoc.options += RDOC_OPTS
|
|
62
68
|
rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/*.rb lib/sequel/*.rb lib/sequel/{connection_pool,dataset,database,model}/*.rb doc/*.rdoc doc/release_notes/*.txt lib/sequel/extensions/migration.rb"
|
|
63
69
|
end
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
rdoc_task_class.new(:website_rdoc_adapters) do |rdoc|
|
|
66
72
|
rdoc.rdoc_dir = "www/public/rdoc-adapters"
|
|
67
73
|
rdoc.options += RDOC_DEFAULT_OPTS + %w'--main Sequel'
|
|
68
74
|
rdoc.rdoc_files.add %w"lib/sequel/adapters/**/*.rb"
|
|
69
75
|
end
|
|
70
76
|
|
|
71
|
-
|
|
77
|
+
rdoc_task_class.new(:website_rdoc_plugins) do |rdoc|
|
|
72
78
|
rdoc.rdoc_dir = "www/public/rdoc-plugins"
|
|
73
79
|
rdoc.options += RDOC_DEFAULT_OPTS + %w'--main Sequel'
|
|
74
80
|
rdoc.rdoc_files.add %w"lib/sequel/{extensions,plugins}/**/*.rb"
|
|
@@ -92,11 +98,13 @@ begin
|
|
|
92
98
|
require "spec/rake/spectask"
|
|
93
99
|
spec_class = Spec::Rake::SpecTask
|
|
94
100
|
spec_files_meth = :spec_files=
|
|
101
|
+
spec_opts_meth = :spec_opts=
|
|
95
102
|
rescue LoadError
|
|
96
103
|
# RSpec 2
|
|
97
104
|
require "rspec/core/rake_task"
|
|
98
105
|
spec_class = RSpec::Core::RakeTask
|
|
99
106
|
spec_files_meth = :pattern=
|
|
107
|
+
spec_opts_meth = :rspec_opts=
|
|
100
108
|
end
|
|
101
109
|
|
|
102
110
|
spec = lambda do |name, files, d|
|
|
@@ -105,25 +113,35 @@ begin
|
|
|
105
113
|
desc d
|
|
106
114
|
spec_class.new(name) do |t|
|
|
107
115
|
t.send spec_files_meth, files
|
|
108
|
-
t.
|
|
116
|
+
t.send spec_opts_meth, ENV['SEQUEL_SPEC_OPTS'].split if ENV['SEQUEL_SPEC_OPTS']
|
|
109
117
|
end
|
|
110
118
|
end
|
|
111
119
|
|
|
112
|
-
spec_with_cov = lambda do |name, files, d|
|
|
120
|
+
sc = spec_with_cov = lambda do |name, files, d|
|
|
113
121
|
spec.call(name, files, d)
|
|
114
122
|
t = spec.call("#{name}_cov", files, "#{d} with coverage")
|
|
115
123
|
t.rcov = true
|
|
116
124
|
t.rcov_opts = File.read("spec/rcov.opts").split("\n")
|
|
125
|
+
t
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
if RUBY_VERSION >= '1.8.7'
|
|
129
|
+
eval <<-END
|
|
130
|
+
spec_with_cov = lambda do |*x, &b|
|
|
131
|
+
t = sc.call(*x)
|
|
132
|
+
b.call(t) if b
|
|
133
|
+
end
|
|
134
|
+
END
|
|
117
135
|
end
|
|
118
136
|
|
|
119
137
|
task :default => [:spec]
|
|
120
|
-
spec_with_cov.call("spec", Dir["spec/{core,model}/*_spec.rb"], "Run core and model specs")
|
|
138
|
+
spec_with_cov.call("spec", Dir["spec/{core,model}/*_spec.rb"], "Run core and model specs"){|t| t.rcov_opts.concat(%w'--exclude "lib/sequel/adapters/([a-ln-z]|m[a-np-z])"')}
|
|
121
139
|
spec.call("spec_core", Dir["spec/core/*_spec.rb"], "Run core specs")
|
|
122
140
|
spec.call("spec_model", Dir["spec/model/*_spec.rb"], "Run model specs")
|
|
123
141
|
spec_with_cov.call("spec_plugin", Dir["spec/extensions/*_spec.rb"], "Run extension/plugin specs")
|
|
124
142
|
spec_with_cov.call("spec_integration", Dir["spec/integration/*_test.rb"], "Run integration tests")
|
|
125
143
|
|
|
126
|
-
%w'postgres sqlite mysql informix oracle firebird mssql'.each do |adapter|
|
|
144
|
+
%w'postgres sqlite mysql informix oracle firebird mssql db2'.each do |adapter|
|
|
127
145
|
spec_with_cov.call("spec_#{adapter}", ["spec/adapters/#{adapter}_spec.rb"] + Dir["spec/integration/*_test.rb"], "Run #{adapter} specs")
|
|
128
146
|
end
|
|
129
147
|
rescue LoadError
|
|
@@ -154,5 +172,5 @@ end
|
|
|
154
172
|
|
|
155
173
|
desc "Check syntax of all .rb files"
|
|
156
174
|
task :check_syntax do
|
|
157
|
-
Dir['**/*.rb'].each{|file| print `#{
|
|
175
|
+
Dir['**/*.rb'].each{|file| print `#{FileUtils::RUBY} -c #{file} | fgrep -v "Syntax OK"`}
|
|
158
176
|
end
|
data/bin/sequel
CHANGED
|
@@ -112,11 +112,7 @@ end
|
|
|
112
112
|
|
|
113
113
|
connect_proc = lambda do |database|
|
|
114
114
|
db = if database.nil? || database.empty?
|
|
115
|
-
|
|
116
|
-
def db.connect(*args); Object.new; end
|
|
117
|
-
db.identifier_input_method = nil
|
|
118
|
-
db.identifier_output_method = nil
|
|
119
|
-
db
|
|
115
|
+
Sequel.connect('mock:///', db_opts)
|
|
120
116
|
elsif File.exist?(database)
|
|
121
117
|
require 'yaml'
|
|
122
118
|
env ||= "development"
|
data/doc/association_basics.rdoc
CHANGED
|
@@ -247,7 +247,7 @@ example is a tree structure:
|
|
|
247
247
|
|
|
248
248
|
class Node
|
|
249
249
|
many_to_one :parent, :class=>self
|
|
250
|
-
one_to_many :children :key=>:parent_id, :class=>self
|
|
250
|
+
one_to_many :children, :key=>:parent_id, :class=>self
|
|
251
251
|
end
|
|
252
252
|
|
|
253
253
|
For many_to_many self_referential associations, it's fairly similar. Here's
|
|
@@ -293,32 +293,6 @@ Examples:
|
|
|
293
293
|
@artist.remove_album(@album)
|
|
294
294
|
@artist.remove_all_albums
|
|
295
295
|
|
|
296
|
-
== Dataset Method
|
|
297
|
-
|
|
298
|
-
In addition to the above methods, associations also add a instance method
|
|
299
|
-
ending in +_dataset+ that returns a dataset representing the objects in the associated table:
|
|
300
|
-
|
|
301
|
-
@album.artist_id
|
|
302
|
-
# 10
|
|
303
|
-
@album.artist_dataset
|
|
304
|
-
# SELECT * FROM artists WHERE (id = 10)
|
|
305
|
-
|
|
306
|
-
@artist.id
|
|
307
|
-
# 20
|
|
308
|
-
@artist.albums_dataset
|
|
309
|
-
# SELECT * FROM albums WHERE (artist_id = 20)
|
|
310
|
-
|
|
311
|
-
The association dataset is just like any other Sequel dataset, in that
|
|
312
|
-
it can be further filtered, ordered, etc.:
|
|
313
|
-
|
|
314
|
-
@artist.albums_dataset.
|
|
315
|
-
filter(:name.like('A%')).
|
|
316
|
-
order(:copies_sold).
|
|
317
|
-
limit(10)
|
|
318
|
-
# SELECT * FROM albums
|
|
319
|
-
# WHERE ((artist_id = 20) AND (name LIKE 'A%'))
|
|
320
|
-
# ORDER BY copies_sold LIMIT 10
|
|
321
|
-
|
|
322
296
|
== Caching
|
|
323
297
|
|
|
324
298
|
Associations are cached after being retrieved:
|
|
@@ -352,13 +326,150 @@ instance method:
|
|
|
352
326
|
@album.artists # [<Artist ...>, ...]
|
|
353
327
|
@album.associations[:artists] # [<Artist ...>, ...]
|
|
354
328
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
329
|
+
== Dataset Method
|
|
330
|
+
|
|
331
|
+
In addition to the above methods, associations also add a instance method
|
|
332
|
+
ending in +_dataset+ that returns a dataset representing the objects in the associated table:
|
|
333
|
+
|
|
334
|
+
@album.artist_id
|
|
335
|
+
# 10
|
|
336
|
+
@album.artist_dataset
|
|
337
|
+
# SELECT * FROM artists WHERE (id = 10)
|
|
338
|
+
|
|
339
|
+
@artist.id
|
|
340
|
+
# 20
|
|
341
|
+
@artist.albums_dataset
|
|
342
|
+
# SELECT * FROM albums WHERE (artist_id = 20)
|
|
343
|
+
|
|
344
|
+
The association dataset is just like any other Sequel dataset, in that
|
|
345
|
+
it can be further filtered, ordered, etc.:
|
|
346
|
+
|
|
347
|
+
@artist.albums_dataset.
|
|
348
|
+
filter(:name.like('A%')).
|
|
349
|
+
order(:copies_sold).
|
|
350
|
+
limit(10)
|
|
351
|
+
# SELECT * FROM albums
|
|
352
|
+
# WHERE ((artist_id = 20) AND (name LIKE 'A%'))
|
|
353
|
+
# ORDER BY copies_sold LIMIT 10
|
|
354
|
+
|
|
355
|
+
Records retrieved using the +_dataset+ method are not cached in the
|
|
356
|
+
associations cache.
|
|
358
357
|
|
|
359
358
|
@album.artists_dataset.all # [<Artist ...>, ...]
|
|
360
359
|
@album.associations[:artists] # nil
|
|
361
360
|
|
|
361
|
+
== Dynamic Association Modification
|
|
362
|
+
|
|
363
|
+
Similar to the +_dataset+ method, you can provide a block to the association
|
|
364
|
+
method to customize the dataset that will be used to retrieve the records. So
|
|
365
|
+
you can apply a filter in either of these two ways:
|
|
366
|
+
|
|
367
|
+
@artist.albums_dataset.filter(:name.like('A%'))
|
|
368
|
+
@artist.albums{|ds| ds.filter(:name.like('A%'))}
|
|
369
|
+
|
|
370
|
+
While they both apply the same filter, using the +_dataset+ method does not
|
|
371
|
+
apply any of the association callbacks or handle association reciprocals (see
|
|
372
|
+
below for details about callbacks and reciprocals). Using a block instead handles
|
|
373
|
+
all those things, and also caches its results in the associations cache (ignoring
|
|
374
|
+
any previously cached value).
|
|
375
|
+
|
|
376
|
+
Note that if you are using ruby 1.8.6, you can't pass a block to the association
|
|
377
|
+
method, you have to pass a proc as an argument:
|
|
378
|
+
|
|
379
|
+
@artist.albums(proc{|ds| ds.filter(:name.like('A%'))})
|
|
380
|
+
|
|
381
|
+
== Filtering By Associations
|
|
382
|
+
|
|
383
|
+
In addition to using the association method to get associated objects, you
|
|
384
|
+
can also use associated objects in filters. For example, to get
|
|
385
|
+
all albums for a given artist, you would usually do:
|
|
386
|
+
|
|
387
|
+
@artist.albums
|
|
388
|
+
# or @artist.albums_dataset for a dataset
|
|
389
|
+
|
|
390
|
+
You can also do the following:
|
|
391
|
+
|
|
392
|
+
Album.filter(:artist=>@artist).all
|
|
393
|
+
# or leave off the .all for a dataset
|
|
394
|
+
|
|
395
|
+
For filtering by a single association, this isn't very useful. However, unlike
|
|
396
|
+
using the association method, using a filter allows you to filter by multiple
|
|
397
|
+
associations:
|
|
398
|
+
|
|
399
|
+
Album.filter(:artist=>@artist, :publisher=>@publisher)
|
|
400
|
+
|
|
401
|
+
This will return all albums by that artist and published by that publisher.
|
|
402
|
+
This isn't possible using just the association method approach, though you
|
|
403
|
+
can combine the approaches:
|
|
404
|
+
|
|
405
|
+
@artist.albums_dataset.filter(:publisher=>@publisher)
|
|
406
|
+
|
|
407
|
+
This doesn't just work for +many_to_one+ associations, it also works for
|
|
408
|
+
+one_to_one+, +one_to_many+, and +many_to_many+ associations:
|
|
409
|
+
|
|
410
|
+
Album.one_to_one :album_info
|
|
411
|
+
# The album related to that AlbumInfo instance
|
|
412
|
+
Album.filter(:album_info=>AlbumInfo[2])
|
|
413
|
+
|
|
414
|
+
Album.one_to_many :tracks
|
|
415
|
+
# The album related to that Track instance
|
|
416
|
+
Album.filter(:tracks=>Track[3])
|
|
417
|
+
|
|
418
|
+
Album.many_to_many :tags
|
|
419
|
+
# All albums related to that Tag instance
|
|
420
|
+
Album.filter(:tags=>Tag[4])
|
|
421
|
+
|
|
422
|
+
Note that for +one_to_many+ and +many_to_many+ associations, you still
|
|
423
|
+
use the plural form even though only a single model object is given.
|
|
424
|
+
|
|
425
|
+
You can also exclude by associations:
|
|
426
|
+
|
|
427
|
+
Album.exclude(:artist=>@artist).all
|
|
428
|
+
|
|
429
|
+
This will return all albums not by that artist.
|
|
430
|
+
|
|
431
|
+
You can also provide an array with multiple model objects:
|
|
432
|
+
|
|
433
|
+
Album.filter(:artist=>[@artist1, @artist2]).all
|
|
434
|
+
|
|
435
|
+
Similar to using an array of integers or strings, this will return
|
|
436
|
+
all albums whose artist is one of those two artists. You can also
|
|
437
|
+
use +exclude+ if you want all albums not by either of those artists:
|
|
438
|
+
|
|
439
|
+
Album.exclude(:artist=>[@artist1, @artist2]).all
|
|
440
|
+
|
|
441
|
+
If you are using a +one_to_many+ or +many_to_many+ association, you
|
|
442
|
+
may want to return records where the records matches all of multiple
|
|
443
|
+
records, instead of matching any of them. For example:
|
|
444
|
+
|
|
445
|
+
Album.filter(:tags=>[@tag1, @tag2])
|
|
446
|
+
|
|
447
|
+
This matches albums that are associated with either @tag1 or @tag2 or
|
|
448
|
+
both. If you only want ones that you are associated with both, you can
|
|
449
|
+
use separate filter calls:
|
|
450
|
+
|
|
451
|
+
Album.filter(:tags=>@tag1).filter(:tags=>@tag2)
|
|
452
|
+
|
|
453
|
+
Or the the array form of condition specifiers:
|
|
454
|
+
|
|
455
|
+
Album.filter([[:tags, @tag1], [:tags, @tag2]])
|
|
456
|
+
|
|
457
|
+
These will return albums associated with both @tag1 and @tag2.
|
|
458
|
+
|
|
459
|
+
You can also provide a dataset value when filtering by associations:
|
|
460
|
+
|
|
461
|
+
Album.filter(:artist=>Artist.filter(:name.like('A%'))).all
|
|
462
|
+
|
|
463
|
+
This will return all albums whose artist starts with 'A'. Like
|
|
464
|
+
the other forms, this can be inverted:
|
|
465
|
+
|
|
466
|
+
Album.exclude(:artist=>Artist.filter(:name.like('A%'))).all
|
|
467
|
+
|
|
468
|
+
This will return all albums whose artist does not start with 'A'.
|
|
469
|
+
|
|
470
|
+
Note that filtering by associations only works correctly for simple
|
|
471
|
+
associations (ones without conditions).
|
|
472
|
+
|
|
362
473
|
== Name Collisions
|
|
363
474
|
|
|
364
475
|
Because associations create instance methods, it's possible to override
|
|
@@ -368,7 +479,7 @@ would be bad association names.
|
|
|
368
479
|
|
|
369
480
|
== Database Schema
|
|
370
481
|
|
|
371
|
-
Creating an association
|
|
482
|
+
Creating an association doesn't modify the database schema. Sequel
|
|
372
483
|
assumes your associations reflect the existing database schema. If not,
|
|
373
484
|
you should modify your schema before creating the associations.
|
|
374
485
|
|
|
@@ -1055,7 +1166,7 @@ when eager loading via eager_graph, but called when eager loading via eager.
|
|
|
1055
1166
|
class Artist
|
|
1056
1167
|
# Cache all album names to a single string when retrieving the
|
|
1057
1168
|
# albums.
|
|
1058
|
-
one_to_many :albums, :
|
|
1169
|
+
one_to_many :albums, :after_load=>:cache_album_names
|
|
1059
1170
|
|
|
1060
1171
|
attr_reader :album_names
|
|
1061
1172
|
|
|
@@ -1218,25 +1329,44 @@ a JOIN USING or NATURAL JOIN for the graph:
|
|
|
1218
1329
|
Artist.one_to_many :albums, :key=>:artist_name,
|
|
1219
1330
|
:graph_only_conditions=>nil, :graph_join_type=>:natural
|
|
1220
1331
|
|
|
1332
|
+
==== :graph_alias_base
|
|
1333
|
+
|
|
1334
|
+
The base name to use for the table alias when eager graphing. Defaults to the name
|
|
1335
|
+
of the association. If the alias name has already been used in the query, Sequel will create
|
|
1336
|
+
a unique alias by appending a numeric suffix (e.g. alias_0, alias_1, ...) until the alias is
|
|
1337
|
+
unique.
|
|
1338
|
+
|
|
1339
|
+
This is mostly useful if you have associations with the same name in many models, and you want
|
|
1340
|
+
to be able to easily tell which table alias corresponds to which association when eagerly
|
|
1341
|
+
graphing multiple associations with the same name.
|
|
1342
|
+
|
|
1221
1343
|
==== :eager_grapher
|
|
1222
1344
|
|
|
1223
1345
|
Sets up a custom grapher to use when eager loading the objects via eager_graph.
|
|
1224
|
-
This is the eager_graph analogue to the :eager_loader option.
|
|
1346
|
+
This is the eager_graph analogue to the :eager_loader option. This isn't generally
|
|
1347
|
+
needed, as one of the other eager_graph related association options is usually sufficient.
|
|
1225
1348
|
|
|
1226
|
-
If specified, should be a proc that accepts three three arguments
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1349
|
+
If specified, should be a proc that accepts one or three three arguments.
|
|
1350
|
+
If the proc takes one argument, it will be given a hash with the following keys:
|
|
1351
|
+
|
|
1352
|
+
:self :: The dataset that is doing the eager loading
|
|
1353
|
+
:table_alias :: An alias to use for the table to graph for this association.
|
|
1354
|
+
:implicit_qualifier :: The alias that was used for the current table (since you can cascade associations).
|
|
1355
|
+
:callback :: A callback proc used to dynamically modify the dataset to graph into the
|
|
1356
|
+
current dataset, before such graphing is done. This is nil if no callback
|
|
1357
|
+
proc is used.
|
|
1358
|
+
|
|
1359
|
+
If the proc takes three arguments, it gets passed the :self, :association_alias,
|
|
1360
|
+
and :table_alias values. The 3 argument procs are allowed for backwards
|
|
1361
|
+
compatibility, and it is recommended to use the 1 argument proc format
|
|
1362
|
+
for new code.
|
|
1230
1363
|
|
|
1231
1364
|
Artist.one_to_many :self_title_albums, :class=>:Album,
|
|
1232
|
-
:eager_grapher=>(proc do |
|
|
1233
|
-
|
|
1234
|
-
:table_alias=>
|
|
1365
|
+
:eager_grapher=>(proc do |eo|
|
|
1366
|
+
eo[:self].graph(Album, {:artist_id=>:id, :name=>:name},
|
|
1367
|
+
:table_alias=>eo[:table_alias], :implicit_qualifier=>eo[:implicit_qualifier])
|
|
1235
1368
|
end)
|
|
1236
1369
|
|
|
1237
|
-
This isn't generally needed, as one of the other eager_graph related
|
|
1238
|
-
association options is usually sufficient.
|
|
1239
|
-
|
|
1240
1370
|
==== :order_eager_graph
|
|
1241
1371
|
|
|
1242
1372
|
Whether to add the order to the dataset's order when graphing via eager_graph.
|
|
@@ -1353,6 +1483,34 @@ If the default modification methods would not do what you want, and you
|
|
|
1353
1483
|
don't plan on overriding the internal modification methods to do what you
|
|
1354
1484
|
want, it may be best to set this option to true.
|
|
1355
1485
|
|
|
1486
|
+
==== :key_column [+many_to_one+]
|
|
1487
|
+
|
|
1488
|
+
This option exists to make it possible to create a +many_to_one+ association
|
|
1489
|
+
with the same name as the foreign key it uses. Before this option was
|
|
1490
|
+
introduced, this was problematic, since the :key option was used to refer
|
|
1491
|
+
both to the model methods and the underlying database columns (which are
|
|
1492
|
+
usually the same).
|
|
1493
|
+
|
|
1494
|
+
If you have a legacy database with a foreign key that is the same as the name
|
|
1495
|
+
of the association you would like to use, you should create a column alias
|
|
1496
|
+
for the foreign key and use this option:
|
|
1497
|
+
|
|
1498
|
+
# Example schema:
|
|
1499
|
+
# albums artists
|
|
1500
|
+
# :id /--> :id
|
|
1501
|
+
# :artist --/ :name
|
|
1502
|
+
# :name
|
|
1503
|
+
|
|
1504
|
+
class Album < Sequel::Model
|
|
1505
|
+
def_column_alias(:artist_id, :artist)
|
|
1506
|
+
many_to_one :artist, :key_column=>:artist
|
|
1507
|
+
end
|
|
1508
|
+
|
|
1509
|
+
Note that if you have control over the database, it's better to just rename
|
|
1510
|
+
the foreign key column than use this option. Similarly, if you can think
|
|
1511
|
+
of another association name that will work, it's wiser to rename the
|
|
1512
|
+
association than use this option. Think of this option as a last resort.
|
|
1513
|
+
|
|
1356
1514
|
==== :validate
|
|
1357
1515
|
|
|
1358
1516
|
Set to false to not validate when implicitly saving any associated object.
|
|
@@ -1399,3 +1557,51 @@ associations depends on another plugin that defines instance methods of
|
|
|
1399
1557
|
the same name. In that case, the instance methods of the dependent
|
|
1400
1558
|
plugin would override the association methods created by the main
|
|
1401
1559
|
plugin.
|
|
1560
|
+
|
|
1561
|
+
==== :eager_limit_strategy
|
|
1562
|
+
|
|
1563
|
+
This setting determines what strategy to use for loading the associations
|
|
1564
|
+
that use the :limit setting to limit the number of returned records. You
|
|
1565
|
+
can't use LIMIT directly, since you want a limit for each associated
|
|
1566
|
+
record, not a LIMIT on the number of records returned by the dataset.
|
|
1567
|
+
|
|
1568
|
+
By default, no strategy is used for one_to_one associations, and
|
|
1569
|
+
the :ruby strategy is used for *_many associations, which does a simple
|
|
1570
|
+
array slice after loading the associated records. That doesn't provide
|
|
1571
|
+
a performance advantage, since all records are still loaded from the
|
|
1572
|
+
database, but it at least makes sure the cached records are accurately
|
|
1573
|
+
limited as they would be in the lazy load case.
|
|
1574
|
+
|
|
1575
|
+
The reason no strategy is used by default for one_to_one associations
|
|
1576
|
+
is that none is needed for a true one_to_one association (since there
|
|
1577
|
+
is only one associated record per current record). However, if you are
|
|
1578
|
+
using a one_to_one association where the relationship is really one_to_many,
|
|
1579
|
+
and using an order to pick the first matching row, then if you don't
|
|
1580
|
+
specify an :eager_limit_strategy option, you'll be loading all related
|
|
1581
|
+
rows just to have Sequel ignore all rows after the first. By using a
|
|
1582
|
+
strategy to change the query to only return one associated record per
|
|
1583
|
+
current record, you can get much better database performance.
|
|
1584
|
+
|
|
1585
|
+
You can set a value of +true+ for this option to have Sequel select what
|
|
1586
|
+
it thinks is the best way of limiting the records for your database. You
|
|
1587
|
+
can also specify a symbol to manually choose a strategy. The available
|
|
1588
|
+
strategies are:
|
|
1589
|
+
|
|
1590
|
+
:distinct_on :: Uses DISTINCT ON to ensure only the first matching record
|
|
1591
|
+
is loaded (one_to_one associations only). This is used by
|
|
1592
|
+
default on PostgreSQL.
|
|
1593
|
+
:window_function :: Uses window functions if the database supports it.
|
|
1594
|
+
This is used by default on databases that support window
|
|
1595
|
+
functions.
|
|
1596
|
+
:correlated_subquery :: Uses a correlated subquery to get the information.
|
|
1597
|
+
This is never used by default as if you aren't careful,
|
|
1598
|
+
it can result in pathologically long running times
|
|
1599
|
+
This will not work correctly for association where
|
|
1600
|
+
the associated table has a composite primary key if
|
|
1601
|
+
the database doesn't support using IN
|
|
1602
|
+
with multiple columns. This will also not work on MySQL
|
|
1603
|
+
because MySQL has problems using IN with a correlated
|
|
1604
|
+
subquery that contains a limit.
|
|
1605
|
+
:ruby :: Uses ruby array slicing to emulate database limiting (*_many
|
|
1606
|
+
associations only). This is the default if the database doesn't
|
|
1607
|
+
support window functions.
|
data/doc/dataset_basics.rdoc
CHANGED
|
@@ -74,12 +74,12 @@ Most Dataset methods that users will use can be broken down into two types:
|
|
|
74
74
|
|
|
75
75
|
Most dataset methods fall into this category, which can be further broken down by the clause they affect:
|
|
76
76
|
|
|
77
|
-
SELECT:: select, select_all, select_append, select_more
|
|
77
|
+
SELECT:: select, select_all, select_append, select_group, select_more
|
|
78
78
|
FROM:: from, from_self
|
|
79
79
|
JOIN:: join, left_join, right_join, full_join, natural_join, natural_left_join, natural_right_join, natural_full_join, cross_join, inner_join, left_outer_join, right_outer_join, full_outer_join, join_table
|
|
80
|
-
WHERE:: where, filter, exclude, and, or, grep, invert, unfiltered
|
|
81
|
-
GROUP:: group, group_by, group_and_count, ungrouped
|
|
82
|
-
HAVING:: having, filter, exclude, and, or, grep, invert, unfiltered
|
|
80
|
+
WHERE:: where, filter, exclude, exclude_where, and, or, grep, invert, unfiltered
|
|
81
|
+
GROUP:: group, group_by, group_and_count, select_group, ungrouped
|
|
82
|
+
HAVING:: having, filter, exclude, exclude_having, and, or, grep, invert, unfiltered
|
|
83
83
|
ORDER:: order, order_by, order_append, order_prepend, order_more, reverse, reverse_order, unordered
|
|
84
84
|
LIMIT:: limit, unlimited
|
|
85
85
|
compounds:: union, intersect, except
|
data/doc/dataset_filtering.rdoc
CHANGED
|
@@ -59,6 +59,14 @@ Ranges (both inclusive and exclusive) can also be used:
|
|
|
59
59
|
items.filter(:price => 100...200).sql
|
|
60
60
|
#=> "SELECT * FROM items WHERE (price >= 100 AND price < 200)"
|
|
61
61
|
|
|
62
|
+
== Filtering using an array
|
|
63
|
+
|
|
64
|
+
If you need to select multiple items from a dataset, you can supply an array:
|
|
65
|
+
|
|
66
|
+
item_array = [1, 38, 47, 99]
|
|
67
|
+
items.filter(:id => item_array).sql
|
|
68
|
+
#=> "SELECT * FROM items WHERE (id IN (1, 38, 47, 99))"
|
|
69
|
+
|
|
62
70
|
== Filtering using expressions
|
|
63
71
|
|
|
64
72
|
Sequel allows you to use ruby expressions directly in the call to filter:
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
= Sequel::Model Mass Assignment
|
|
2
|
+
|
|
3
|
+
Most Model methods that take a hash of attribute keys and values, including <tt>Model.new</tt>, <tt>Model.create</tt>, <tt>Model#set</tt> and <tt>Model#update</tt> are subject to Sequel's mass assignment rules.
|
|
4
|
+
When you pass a hash to these methods, each key has an <tt>=</tt> appended to it (the setter method), and if the setter method exists and access to it is not restricted, Sequel will call the setter method with the hash value.
|
|
5
|
+
By default, there are two types of setter methods that are restricted.
|
|
6
|
+
The first is methods like <tt>typecast_on_assignment=</tt> and <tt>==</tt>, which don't affect columns.
|
|
7
|
+
These methods cannot be enabled for mass assignment.
|
|
8
|
+
The second is primary key setters.
|
|
9
|
+
To enable use of primary key setters, you need to call +unrestrict_primary_key+ for that model:
|
|
10
|
+
|
|
11
|
+
Post.unrestrict_primary_key
|
|
12
|
+
|
|
13
|
+
Since mass assignment by default allows modification of all column values except for primary key columns, it can be a security risk in some cases.
|
|
14
|
+
Sequel has multiple ways of securing mass assignment.
|
|
15
|
+
The first way is using +set_allowed_columns+:
|
|
16
|
+
|
|
17
|
+
Post.set_allowed_columns :title, :body, :category
|
|
18
|
+
|
|
19
|
+
This explicitly sets which methods are allowed (<tt>title=</tt>, <tt>body=</tt>, and <tt>category=</tt>), all other methods will not be allowed.
|
|
20
|
+
This method is useful in simple applications where the same columns are allowed in all cases, but not appropriate when different columns are allowed in different scenarios (e.g. admin access vs. user access).
|
|
21
|
+
To handle cases where different columns are allowed in different cases, you can use +set_only+ or +update_only+:
|
|
22
|
+
|
|
23
|
+
# user case
|
|
24
|
+
post.set_only(params[:post], :title, :body)
|
|
25
|
+
# admin case
|
|
26
|
+
post.set_only(params[:post], :title, :body, :deleted)
|
|
27
|
+
|
|
28
|
+
In this case, only the <tt>title=</tt> and <tt>body=</tt> methods will be allowed in the mass assignment.
|
|
29
|
+
|
|
30
|
+
By default, if an invalid setter method call is attempted, Sequel raises a <tt>Sequel::Error</tt> exception. You can have Sequel silently ignore invalid calls by doing:
|
|
31
|
+
|
|
32
|
+
# Global default
|
|
33
|
+
Sequel::Model.strict_param_setting = false
|
|
34
|
+
# Class level
|
|
35
|
+
Post.strict_param_setting = false
|
|
36
|
+
# Instance level
|
|
37
|
+
post.strict_param_setting = false
|
|
38
|
+
|
|
39
|
+
These mass assignment methods have been around a long time, but starting in Sequel 3.12.0, the +set_fields+ or +update_fields+ methods were added, and these may be a better mass assignment choice for most users.
|
|
40
|
+
These methods take two arguments, the attributes hash as the first argument, and a single array of valid field names as the second argument:
|
|
41
|
+
|
|
42
|
+
post.set_fields(params[:post], [:title, :body])
|
|
43
|
+
|
|
44
|
+
+set_fields+ and +update_fields+ differ in implementation from +set_only+ and +update_only+.
|
|
45
|
+
With +set_only+ and +update_only+, the hash is iterated over and it checks each method call attempt to see if it is valid.
|
|
46
|
+
With +set_fields+ and +update_fields+, the array is iterated over, and it just looks up the value in the hash and calls the appropriate setter method.
|
|
47
|
+
|
|
48
|
+
+set_fields+ and +update_fields+ are designed for the case where you are expecting specific fields in the input, and want to ignore the other fields.
|
|
49
|
+
They work great for things like HTML forms where the form fields are static.
|
|
50
|
+
+set_only+ and +update_only+ are designed for cases where you are not sure what fields are going to be present in the input, but still want to make sure only certain setter methods can be called.
|
|
51
|
+
They work great for flexible APIs.
|
|
52
|
+
|
|
53
|
+
In all of the mass assignment cases, methods starting with +set+ will set the attributes without saving the object, while methods starting with +update+ will set the attributes and then save the changes to the object.
|
|
54
|
+
|