sequel 1.5.1 → 2.0.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 +30 -0
- data/README +12 -15
- data/Rakefile +9 -20
- data/lib/sequel_model.rb +47 -72
- data/lib/sequel_model/association_reflection.rb +59 -0
- data/lib/sequel_model/associations.rb +99 -94
- data/lib/sequel_model/base.rb +308 -102
- data/lib/sequel_model/caching.rb +72 -27
- data/lib/sequel_model/eager_loading.rb +308 -300
- data/lib/sequel_model/hooks.rb +51 -49
- data/lib/sequel_model/inflector.rb +186 -182
- data/lib/sequel_model/plugins.rb +54 -40
- data/lib/sequel_model/record.rb +185 -220
- data/lib/sequel_model/schema.rb +27 -34
- data/lib/sequel_model/validations.rb +54 -73
- data/spec/association_reflection_spec.rb +85 -0
- data/spec/associations_spec.rb +160 -73
- data/spec/base_spec.rb +3 -3
- data/spec/eager_loading_spec.rb +132 -35
- data/spec/hooks_spec.rb +120 -20
- data/spec/inflector_spec.rb +2 -2
- data/spec/model_spec.rb +110 -78
- data/spec/plugins_spec.rb +4 -0
- data/spec/rcov.opts +1 -1
- data/spec/record_spec.rb +160 -59
- data/spec/spec.opts +0 -5
- data/spec/spec_helper.rb +12 -0
- data/spec/validations_spec.rb +23 -0
- metadata +60 -50
- data/lib/sequel_model/deprecated.rb +0 -81
- data/lib/sequel_model/inflections.rb +0 -112
- data/spec/deprecated_relations_spec.rb +0 -113
data/lib/sequel_model/plugins.rb
CHANGED
@@ -1,48 +1,62 @@
|
|
1
1
|
module Sequel
|
2
|
-
|
2
|
+
# Empty namespace that plugins should use to store themselves,
|
3
|
+
# so they can be loaded via Model.is.
|
4
|
+
#
|
5
|
+
# Plugins should be modules with one of the following conditions:
|
6
|
+
# * A singleton method named apply, which takes a model and
|
7
|
+
# additional arguments.
|
8
|
+
# * A module inside the plugin module named InstanceMethods,
|
9
|
+
# which will be included in the model class.
|
10
|
+
# * A module inside the plugin module named ClassMethods,
|
11
|
+
# which will extend the model class.
|
12
|
+
# * A module inside the plugin module named DatasetMethods,
|
13
|
+
# which will extend the model's dataset.
|
14
|
+
module Plugins
|
15
|
+
end
|
3
16
|
|
4
17
|
class Model
|
5
|
-
class
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
dataset.metaclass.send(:include, m::DatasetMethods)
|
27
|
-
end
|
18
|
+
# Loads a plugin for use with the model class, passing optional arguments
|
19
|
+
# to the plugin. If the plugin has a DatasetMethods module and the model
|
20
|
+
# doesn't have a dataset, raise an Error.
|
21
|
+
def self.is(plugin, *args)
|
22
|
+
m = plugin_module(plugin)
|
23
|
+
raise(Error, "Plugin cannot be applied because the model class has no dataset") if m.const_defined?("DatasetMethods") && !@dataset
|
24
|
+
if m.respond_to?(:apply)
|
25
|
+
m.apply(self, *args)
|
26
|
+
end
|
27
|
+
if m.const_defined?("InstanceMethods")
|
28
|
+
class_def(:"#{plugin}_opts") {args.first}
|
29
|
+
include(m::InstanceMethods)
|
30
|
+
end
|
31
|
+
if m.const_defined?("ClassMethods")
|
32
|
+
meta_def(:"#{plugin}_opts") {args.first}
|
33
|
+
extend(m::ClassMethods)
|
34
|
+
end
|
35
|
+
if m.const_defined?("DatasetMethods")
|
36
|
+
dataset.meta_def(:"#{plugin}_opts") {args.first}
|
37
|
+
dataset.metaclass.send(:include, m::DatasetMethods)
|
38
|
+
def_dataset_method(*m::DatasetMethods.instance_methods)
|
28
39
|
end
|
29
|
-
|
30
|
-
|
31
|
-
private
|
32
|
-
# Returns the module for the specified plugin. If the module is not
|
33
|
-
# defined, the corresponding plugin gem is automatically loaded.
|
34
|
-
def plugin_module(plugin)
|
35
|
-
module_name = plugin.to_s.gsub(/(^|_)(.)/) {$2.upcase}
|
36
|
-
if not Sequel::Plugins.const_defined?(module_name)
|
37
|
-
require plugin_gem(plugin)
|
38
|
-
end
|
39
|
-
Sequel::Plugins.const_get(module_name)
|
40
|
-
end
|
40
|
+
end
|
41
|
+
metaalias :is_a, :is
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
### Private Class Methods ###
|
44
|
+
|
45
|
+
# Returns the gem name for the given plugin.
|
46
|
+
def self.plugin_gem(plugin) # :nodoc:
|
47
|
+
"sequel_#{plugin}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the module for the specified plugin. If the module is not
|
51
|
+
# defined, the corresponding plugin gem is automatically loaded.
|
52
|
+
def self.plugin_module(plugin) # :nodoc:
|
53
|
+
module_name = plugin.to_s.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
|
54
|
+
if not Sequel::Plugins.const_defined?(module_name)
|
55
|
+
require plugin_gem(plugin)
|
56
|
+
end
|
57
|
+
Sequel::Plugins.const_get(module_name)
|
46
58
|
end
|
59
|
+
|
60
|
+
metaprivate :plugin_gem, :plugin_module
|
47
61
|
end
|
48
62
|
end
|
data/lib/sequel_model/record.rb
CHANGED
@@ -1,13 +1,56 @@
|
|
1
|
+
# This file holds general instance methods for Sequel::Model
|
2
|
+
|
1
3
|
module Sequel
|
2
4
|
class Model
|
3
|
-
|
5
|
+
# The columns that have been updated. This isn't completely accurate,
|
6
|
+
# see Model#[]=.
|
4
7
|
attr_reader :changed_columns
|
5
8
|
|
6
|
-
#
|
9
|
+
# The hash of attribute values. Keys are symbols with the names of the
|
10
|
+
# underlying database columns.
|
11
|
+
attr_reader :values
|
12
|
+
|
13
|
+
# Whether this model instance should typecast on attribute assignment
|
14
|
+
attr_writer :typecast_on_assignment
|
15
|
+
|
16
|
+
class_attr_reader :columns, :dataset, :db, :primary_key, :str_columns
|
17
|
+
|
18
|
+
# Creates new instance with values set to passed-in Hash.
|
19
|
+
# If a block is given, yield the instance to the block.
|
20
|
+
# This method runs the after_initialize hook after
|
21
|
+
# it has optionally yielded itself to the block.
|
22
|
+
#
|
23
|
+
# Arguments:
|
24
|
+
# * values - should be a hash with symbol keys, though
|
25
|
+
# string keys will work if from_db is false.
|
26
|
+
# * from_db - should only be set by Model.load, forget it
|
27
|
+
# exists.
|
28
|
+
def initialize(values = nil, from_db = false, &block)
|
29
|
+
values ||= {}
|
30
|
+
@changed_columns = []
|
31
|
+
@typecast_on_assignment = model.typecast_on_assignment
|
32
|
+
@db_schema = model.db_schema
|
33
|
+
if from_db
|
34
|
+
@new = false
|
35
|
+
@values = values
|
36
|
+
else
|
37
|
+
@values = {}
|
38
|
+
@new = true
|
39
|
+
set_with_params(values)
|
40
|
+
end
|
41
|
+
@changed_columns.clear
|
42
|
+
|
43
|
+
yield self if block
|
44
|
+
after_initialize
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns value of the column's attribute.
|
7
48
|
def [](column)
|
8
49
|
@values[column]
|
9
50
|
end
|
10
|
-
|
51
|
+
|
52
|
+
# Sets value of the column's attribute and marks the column as changed.
|
53
|
+
# If the column already has the same value, this is a no-op.
|
11
54
|
def []=(column, value)
|
12
55
|
# If it is new, it doesn't have a value yet, so we should
|
13
56
|
# definitely set the new value.
|
@@ -15,27 +58,10 @@ module Sequel
|
|
15
58
|
# NULL in the database, so assume it has changed.
|
16
59
|
if new? || !@values.include?(column) || value != @values[column]
|
17
60
|
@changed_columns << column unless @changed_columns.include?(column)
|
18
|
-
@values[column] = value
|
61
|
+
@values[column] = typecast_value(column, value)
|
19
62
|
end
|
20
63
|
end
|
21
64
|
|
22
|
-
# Enumerates through all attributes.
|
23
|
-
#
|
24
|
-
# === Example:
|
25
|
-
# Ticket.find(7).each { |k, v| puts "#{k} => #{v}" }
|
26
|
-
def each(&block)
|
27
|
-
@values.each(&block)
|
28
|
-
end
|
29
|
-
# Returns attribute names.
|
30
|
-
def keys
|
31
|
-
@values.keys
|
32
|
-
end
|
33
|
-
|
34
|
-
# Returns value for <tt>:id</tt> attribute.
|
35
|
-
def id
|
36
|
-
@values[:id]
|
37
|
-
end
|
38
|
-
|
39
65
|
# Compares model instances by values.
|
40
66
|
def ==(obj)
|
41
67
|
(obj.class == model) && (obj.values == @values)
|
@@ -48,201 +74,126 @@ module Sequel
|
|
48
74
|
pk.nil? ? false : (obj.class == model) && (obj.pk == pk)
|
49
75
|
end
|
50
76
|
|
51
|
-
#
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
77
|
+
# class is defined in Object, but it is also a keyword,
|
78
|
+
# and since a lot of instance methods call class methods,
|
79
|
+
# the model makes it so you can use model instead of
|
80
|
+
# self.class.
|
81
|
+
alias_method :model, :class
|
56
82
|
|
57
|
-
#
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
def self.primary_key_hash(value)
|
64
|
-
{:id => value}
|
83
|
+
# Deletes and returns self. Does not run destroy hooks.
|
84
|
+
# Look into using destroy instead.
|
85
|
+
def delete
|
86
|
+
before_delete
|
87
|
+
this.delete
|
88
|
+
self
|
65
89
|
end
|
66
90
|
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
# # regular key
|
77
|
-
# set_primary_key :person_id
|
78
|
-
# end
|
79
|
-
#
|
80
|
-
# <i>You can even set it to nil!</i>
|
81
|
-
def self.set_primary_key(*key)
|
82
|
-
# if k is nil, we go to no_primary_key
|
83
|
-
if key.empty? || (key.size == 1 && key.first == nil)
|
84
|
-
return no_primary_key
|
85
|
-
end
|
86
|
-
|
87
|
-
# backwards compat
|
88
|
-
key = (key.length == 1) ? key[0] : key.flatten
|
89
|
-
|
90
|
-
# redefine primary_key
|
91
|
-
meta_def(:primary_key) {key}
|
92
|
-
|
93
|
-
unless key.is_a? Array # regular primary key
|
94
|
-
class_def(:this) do
|
95
|
-
@this ||= dataset.filter(key => @values[key]).limit(1).naked
|
96
|
-
end
|
97
|
-
class_def(:pk) do
|
98
|
-
@pk ||= @values[key]
|
99
|
-
end
|
100
|
-
class_def(:pk_hash) do
|
101
|
-
@pk ||= {key => @values[key]}
|
102
|
-
end
|
103
|
-
class_def(:cache_key) do
|
104
|
-
pk = @values[key] || (raise Error, 'no primary key for this record')
|
105
|
-
@cache_key ||= "#{self.class}:#{pk}"
|
106
|
-
end
|
107
|
-
meta_def(:primary_key_hash) do |v|
|
108
|
-
{key => v}
|
109
|
-
end
|
110
|
-
else # composite key
|
111
|
-
exp_list = key.map {|k| "#{k.inspect} => @values[#{k.inspect}]"}
|
112
|
-
block = eval("proc {@this ||= self.class.dataset.filter(#{exp_list.join(',')}).limit(1).naked}")
|
113
|
-
class_def(:this, &block)
|
114
|
-
|
115
|
-
exp_list = key.map {|k| "@values[#{k.inspect}]"}
|
116
|
-
block = eval("proc {@pk ||= [#{exp_list.join(',')}]}")
|
117
|
-
class_def(:pk, &block)
|
118
|
-
|
119
|
-
exp_list = key.map {|k| "#{k.inspect} => @values[#{k.inspect}]"}
|
120
|
-
block = eval("proc {@this ||= {#{exp_list.join(',')}}}")
|
121
|
-
class_def(:pk_hash, &block)
|
122
|
-
|
123
|
-
exp_list = key.map {|k| '#{@values[%s]}' % k.inspect}.join(',')
|
124
|
-
block = eval('proc {@cache_key ||= "#{self.class}:%s"}' % exp_list)
|
125
|
-
class_def(:cache_key, &block)
|
126
|
-
|
127
|
-
meta_def(:primary_key_hash) do |v|
|
128
|
-
key.inject({}) {|m, i| m[i] = v.shift; m}
|
129
|
-
end
|
91
|
+
# Like delete but runs hooks before and after delete.
|
92
|
+
# If before_destroy returns false, returns false without
|
93
|
+
# deleting the object the the database. Otherwise, deletes
|
94
|
+
# the item from the database and returns self.
|
95
|
+
def destroy
|
96
|
+
db.transaction do
|
97
|
+
return false if before_destroy == false
|
98
|
+
delete
|
99
|
+
after_destroy
|
130
100
|
end
|
101
|
+
self
|
131
102
|
end
|
132
103
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
class_def(:cache_key) {raise Error, "No primary key is associated with this model"}
|
104
|
+
# Enumerates through all attributes.
|
105
|
+
#
|
106
|
+
# Example:
|
107
|
+
# Ticket.find(7).each { |k, v| puts "#{k} => #{v}" }
|
108
|
+
def each(&block)
|
109
|
+
@values.each(&block)
|
140
110
|
end
|
141
|
-
|
142
|
-
#
|
143
|
-
|
144
|
-
|
145
|
-
obj = new(values, &block)
|
146
|
-
obj.save
|
147
|
-
obj
|
111
|
+
|
112
|
+
# Returns true when current instance exists, false otherwise.
|
113
|
+
def exists?
|
114
|
+
this.count > 0
|
148
115
|
end
|
149
116
|
|
150
|
-
#
|
151
|
-
#
|
152
|
-
|
153
|
-
|
154
|
-
# If no columns have been set for this model (very unlikely), assume symbol
|
155
|
-
# keys are valid column names, and assign the column value based on that.
|
156
|
-
def set_with_params(hash)
|
157
|
-
columns_not_set = !model.instance_variable_get(:@columns)
|
158
|
-
meths = setter_methods
|
159
|
-
hash.each do |k,v|
|
160
|
-
m = "#{k}="
|
161
|
-
if meths.include?(m)
|
162
|
-
send(m, v)
|
163
|
-
elsif columns_not_set && (Symbol === k)
|
164
|
-
self[k] = v
|
165
|
-
end
|
166
|
-
end
|
117
|
+
# Unique for objects with the same class and pk (if pk is not nil), or
|
118
|
+
# the same class and values (if pk is nil).
|
119
|
+
def hash
|
120
|
+
[model, pk.nil? ? @values.sort_by{|k,v| k.to_s} : pk].hash
|
167
121
|
end
|
168
122
|
|
169
|
-
#
|
170
|
-
|
171
|
-
|
172
|
-
|
123
|
+
# Returns value for the :id attribute, even if the primary key is
|
124
|
+
# not id. To get the primary key value, use #pk.
|
125
|
+
def id
|
126
|
+
@values[:id]
|
173
127
|
end
|
174
128
|
|
175
|
-
# Returns
|
176
|
-
|
177
|
-
|
129
|
+
# Returns a string representation of the model instance including
|
130
|
+
# the class name and values.
|
131
|
+
def inspect
|
132
|
+
"#<#{model.name} @values=#{@values.inspect}>"
|
178
133
|
end
|
179
|
-
|
180
|
-
# Returns
|
181
|
-
def
|
182
|
-
|
183
|
-
@cache_key ||= "#{self.class}:#{pk}"
|
134
|
+
|
135
|
+
# Returns attribute names as an array of symbols.
|
136
|
+
def keys
|
137
|
+
@values.keys
|
184
138
|
end
|
185
139
|
|
186
|
-
# Returns
|
187
|
-
def
|
188
|
-
@
|
140
|
+
# Returns true if the current instance represents a new record.
|
141
|
+
def new?
|
142
|
+
@new
|
189
143
|
end
|
190
144
|
|
191
|
-
# Returns the primary key value identifying the model instance.
|
192
|
-
#
|
193
|
-
#
|
145
|
+
# Returns the primary key value identifying the model instance.
|
146
|
+
# Raises an error if this model does not have a primary key.
|
147
|
+
# If the model has a composite primary key, returns an array of values.
|
194
148
|
def pk
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
def pk_hash
|
200
|
-
@pk_hash ||= {:id => @values[:id]}
|
201
|
-
end
|
202
|
-
|
203
|
-
# Creates new instance with values set to passed-in Hash.
|
204
|
-
#
|
205
|
-
# This method guesses whether the record exists when
|
206
|
-
# <tt>new_record</tt> is set to false.
|
207
|
-
def initialize(values = nil, from_db = false, &block)
|
208
|
-
values ||= {}
|
209
|
-
@changed_columns = []
|
210
|
-
if from_db
|
211
|
-
@new = false
|
212
|
-
@values = values
|
149
|
+
raise(Error, "No primary key is associated with this model") unless key = primary_key
|
150
|
+
case key
|
151
|
+
when Array
|
152
|
+
key.collect{|k| @values[k]}
|
213
153
|
else
|
214
|
-
@values
|
215
|
-
@new = true
|
216
|
-
set_with_params(values)
|
154
|
+
@values[key]
|
217
155
|
end
|
218
|
-
@changed_columns.clear
|
219
|
-
|
220
|
-
yield self if block
|
221
|
-
after_initialize
|
222
156
|
end
|
223
157
|
|
224
|
-
#
|
225
|
-
#
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
# Returns true if the current instance represents a new record.
|
231
|
-
def new?
|
232
|
-
@new
|
158
|
+
# Returns a hash identifying the model instance. It should be true that:
|
159
|
+
#
|
160
|
+
# Model[model_instance.pk_hash] === model_instance
|
161
|
+
def pk_hash
|
162
|
+
model.primary_key_hash(pk)
|
233
163
|
end
|
234
164
|
|
235
|
-
#
|
236
|
-
|
237
|
-
|
165
|
+
# Reloads attributes from database and returns self. Also clears all
|
166
|
+
# cached association information. Raises an Error if the record no longer
|
167
|
+
# exists in the database.
|
168
|
+
def refresh
|
169
|
+
@values = this.first || raise(Error, "Record not found")
|
170
|
+
model.all_association_reflections.each do |r|
|
171
|
+
instance_variable_set("@#{r[:name]}", nil)
|
172
|
+
end
|
173
|
+
self
|
238
174
|
end
|
239
|
-
|
240
|
-
|
241
|
-
#
|
175
|
+
alias_method :reload, :refresh
|
176
|
+
|
177
|
+
# Creates or updates the record, after making sure the record
|
178
|
+
# is valid. If the record is not valid, returns false.
|
179
|
+
# If before_save, before_create (if new?), or before_update
|
180
|
+
# (if !new?) return false, returns false. Otherwise,
|
181
|
+
# returns self.
|
242
182
|
def save(*columns)
|
243
|
-
|
183
|
+
return false unless valid?
|
184
|
+
save!(*columns)
|
185
|
+
end
|
186
|
+
|
187
|
+
# Creates or updates the record, without attempting to validate
|
188
|
+
# it first. You can provide an optional list of columns to update,
|
189
|
+
# in which case it only updates those columns.
|
190
|
+
# If before_save, before_create (if new?), or before_update
|
191
|
+
# (if !new?) return false, returns false. Otherwise,
|
192
|
+
# returns self.
|
193
|
+
def save!(*columns)
|
194
|
+
return false if before_save == false
|
244
195
|
if @new
|
245
|
-
before_create
|
196
|
+
return false if before_create == false
|
246
197
|
iid = model.dataset.insert(@values)
|
247
198
|
# if we have a regular primary key and it's not set in @values,
|
248
199
|
# we assume it's the last inserted id
|
@@ -256,7 +207,7 @@ module Sequel
|
|
256
207
|
@new = false
|
257
208
|
after_create
|
258
209
|
else
|
259
|
-
before_update
|
210
|
+
return false if before_update == false
|
260
211
|
if columns.empty?
|
261
212
|
this.update(@values)
|
262
213
|
@changed_columns = []
|
@@ -291,10 +242,10 @@ module Sequel
|
|
291
242
|
when String
|
292
243
|
# Prevent denial of service via memory exhaustion by only
|
293
244
|
# calling to_sym if the symbol already exists.
|
294
|
-
raise(
|
245
|
+
raise(Error, "all string keys must be a valid columns") unless s.include?(k)
|
295
246
|
k.to_sym
|
296
247
|
else
|
297
|
-
raise(
|
248
|
+
raise(Error, "Only symbols and strings allows as keys")
|
298
249
|
end
|
299
250
|
m[k] = v
|
300
251
|
m
|
@@ -303,46 +254,60 @@ module Sequel
|
|
303
254
|
vals
|
304
255
|
end
|
305
256
|
|
257
|
+
# Updates the instance with the supplied values with support for virtual
|
258
|
+
# attributes, ignoring any values for which no setter method is available.
|
259
|
+
# Does not save the record.
|
260
|
+
#
|
261
|
+
# If no columns have been set for this model (very unlikely), assume symbol
|
262
|
+
# keys are valid column names, and assign the column value based on that.
|
263
|
+
def set_with_params(hash)
|
264
|
+
columns_not_set = model.instance_variable_get(:@columns).blank?
|
265
|
+
meths = setter_methods
|
266
|
+
hash.each do |k,v|
|
267
|
+
m = "#{k}="
|
268
|
+
if meths.include?(m)
|
269
|
+
send(m, v)
|
270
|
+
elsif columns_not_set && (Symbol === k)
|
271
|
+
self[k] = v
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# Returns (naked) dataset that should return only this instance.
|
277
|
+
def this
|
278
|
+
@this ||= dataset.filter(pk_hash).limit(1).naked
|
279
|
+
end
|
280
|
+
|
306
281
|
# Sets the values attributes with set_values and then updates
|
307
282
|
# the record in the database using those values. This is a
|
308
283
|
# low level method that does not run the usual save callbacks.
|
309
284
|
# It should probably be avoided. Look into using update_with_params instead.
|
310
285
|
def update_values(values)
|
286
|
+
before_update_values
|
311
287
|
this.update(set_values(values))
|
312
288
|
end
|
313
289
|
|
314
|
-
#
|
315
|
-
def
|
316
|
-
|
317
|
-
|
318
|
-
instance_variable_set("@#{r[:name]}", nil)
|
319
|
-
end
|
320
|
-
self
|
290
|
+
# Runs set_with_params and runs save_changes (which runs any callback methods).
|
291
|
+
def update_with_params(values)
|
292
|
+
set_with_params(values)
|
293
|
+
save_changes
|
321
294
|
end
|
322
|
-
alias_method :reload, :refresh
|
323
295
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
end
|
331
|
-
self
|
296
|
+
private
|
297
|
+
|
298
|
+
# Returns all methods that can be used for attribute
|
299
|
+
# assignment (those that end with =)
|
300
|
+
def setter_methods
|
301
|
+
methods.grep(/=\z/)
|
332
302
|
end
|
333
|
-
|
334
|
-
#
|
335
|
-
#
|
336
|
-
|
337
|
-
|
338
|
-
|
303
|
+
|
304
|
+
# Typecast the value to the column's type if typecasting. Calls the database's
|
305
|
+
# typecast_value method, so database adapters can override/augment the handling
|
306
|
+
# for database specific column types.
|
307
|
+
def typecast_value(column, value)
|
308
|
+
return value unless @typecast_on_assignment && @db_schema && (col_schema = @db_schema[column])
|
309
|
+
raise(Error, "nil/NULL is not allowed for the #{column} column") if value.nil? && (col_schema[:allow_null] == false)
|
310
|
+
model.db.typecast_value(col_schema[:type], value)
|
339
311
|
end
|
340
|
-
|
341
|
-
private
|
342
|
-
# Returns all methods that can be used for attribute
|
343
|
-
# assignment (those that end with =)
|
344
|
-
def setter_methods
|
345
|
-
methods.grep(/=\z/)
|
346
|
-
end
|
347
312
|
end
|
348
313
|
end
|