Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 393 lines (339 sloc) 15.706 kB
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
1 module ActiveRecord
2 module AttributeMethods #:nodoc:
a2875be @brynary Use DependencyModule for included hooks in ActiveRecord
brynary authored
3 extend ActiveSupport::DependencyModule
4
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
5 DEFAULT_SUFFIXES = %w(= ? _before_type_cast)
4db718e @NZKoz Only cache attributes which need it for performance reasons. Closes #…
NZKoz authored
6 ATTRIBUTE_TYPES_CACHED_BY_DEFAULT = [:datetime, :timestamp, :time, :date]
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
7
a2875be @brynary Use DependencyModule for included hooks in ActiveRecord
brynary authored
8 included do
9 attribute_method_suffix(*DEFAULT_SUFFIXES)
10
11 cattr_accessor :attribute_types_cached_by_default, :instance_writer => false
12 self.attribute_types_cached_by_default = ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
13
14 cattr_accessor :time_zone_aware_attributes, :instance_writer => false
15 self.time_zone_aware_attributes = false
16
17 class_inheritable_accessor :skip_time_zone_conversion_for_attributes, :instance_writer => false
18 self.skip_time_zone_conversion_for_attributes = []
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
19 end
20
21 # Declare and check for suffixed attribute methods.
22 module ClassMethods
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
23 # Declares a method available for all attributes with the given suffix.
24 # Uses +method_missing+ and <tt>respond_to?</tt> to rewrite the method
25 #
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
26 # #{attr}#{suffix}(*args, &block)
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
27 #
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
28 # to
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
29 #
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
30 # attribute#{suffix}(#{attr}, *args, &block)
31 #
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
32 # An <tt>attribute#{suffix}</tt> instance method must exist and accept at least
33 # the +attr+ argument.
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
34 #
35 # For example:
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
36 #
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
37 # class Person < ActiveRecord::Base
38 # attribute_method_suffix '_changed?'
39 #
40 # private
41 # def attribute_changed?(attr)
42 # ...
43 # end
44 # end
45 #
46 # person = Person.find(1)
47 # person.name_changed? # => false
48 # person.name = 'Hubert'
49 # person.name_changed? # => true
50 def attribute_method_suffix(*suffixes)
51 attribute_method_suffixes.concat suffixes
52 rebuild_attribute_method_regexp
53 end
54
55 # Returns MatchData if method_name is an attribute method.
56 def match_attribute_method?(method_name)
57 rebuild_attribute_method_regexp unless defined?(@@attribute_method_regexp) && @@attribute_method_regexp
58 @@attribute_method_regexp.match(method_name)
59 end
60
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
61
62 # Contains the names of the generated attribute methods.
63 def generated_methods #:nodoc:
64 @generated_methods ||= Set.new
65 end
66
67 def generated_methods?
68 !generated_methods.empty?
69 end
70
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
71 # Generates all the attribute related methods for columns in the database
72 # accessors, mutators and query methods.
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
73 def define_attribute_methods
74 return if generated_methods?
75 columns_hash.each do |name, column|
b31aa63 Allow column accessors to be created even if Kernel. or Object# metho…
Tobias Lütke authored
76 unless instance_method_already_implemented?(name)
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
77 if self.serialized_attributes[name]
78 define_read_method_for_serialized_attribute(name)
72385a7 @technoweenie Add Time Zone support to ActiveRecord, and config.time_zone property …
technoweenie authored
79 elsif create_time_zone_conversion_attribute?(name, column)
80 define_read_method_for_time_zone_conversion(name)
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
81 else
82 define_read_method(name.to_sym, name, column)
83 end
84 end
85
b31aa63 Allow column accessors to be created even if Kernel. or Object# metho…
Tobias Lütke authored
86 unless instance_method_already_implemented?("#{name}=")
72385a7 @technoweenie Add Time Zone support to ActiveRecord, and config.time_zone property …
technoweenie authored
87 if create_time_zone_conversion_attribute?(name, column)
88 define_write_method_for_time_zone_conversion(name)
89 else
90 define_write_method(name.to_sym)
91 end
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
92 end
93
b31aa63 Allow column accessors to be created even if Kernel. or Object# metho…
Tobias Lütke authored
94 unless instance_method_already_implemented?("#{name}?")
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
95 define_question_method(name)
96 end
97 end
98 end
acbec3e @NZKoz Ensure that custom mutators aren't redefined by define_attribute_meth…
NZKoz authored
99
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
100 # Checks whether the method is defined in the model or any of its subclasses
98dc582 @lifo Merge docrails.
lifo authored
101 # that also derive from Active Record. Raises DangerousAttributeError if the
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
102 # method is defined by Active Record though.
b31aa63 Allow column accessors to be created even if Kernel. or Object# metho…
Tobias Lütke authored
103 def instance_method_already_implemented?(method_name)
240b4c5 @jeremy Ruby 1.9 compat: attribute methods
jeremy authored
104 method_name = method_name.to_s
5b2e8b1 @technoweenie Fix that ActiveRecord would create attribute methods and override cus…
technoweenie authored
105 return true if method_name =~ /^id(=$|\?$|$)/
240b4c5 @jeremy Ruby 1.9 compat: attribute methods
jeremy authored
106 @_defined_class_methods ||= ancestors.first(ancestors.index(ActiveRecord::Base)).sum([]) { |m| m.public_instance_methods(false) | m.private_instance_methods(false) | m.protected_instance_methods(false) }.map(&:to_s).to_set
107 @@_defined_activerecord_methods ||= (ActiveRecord::Base.public_instance_methods(false) | ActiveRecord::Base.private_instance_methods(false) | ActiveRecord::Base.protected_instance_methods(false)).map(&:to_s).to_set
5b2e8b1 @technoweenie Fix that ActiveRecord would create attribute methods and override cus…
technoweenie authored
108 raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord" if @@_defined_activerecord_methods.include?(method_name)
109 @_defined_class_methods.include?(method_name)
b31aa63 Allow column accessors to be created even if Kernel. or Object# metho…
Tobias Lütke authored
110 end
111
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
112 alias :define_read_methods :define_attribute_methods
113
4db718e @NZKoz Only cache attributes which need it for performance reasons. Closes #…
NZKoz authored
114 # +cache_attributes+ allows you to declare which converted attribute values should
115 # be cached. Usually caching only pays off for attributes with expensive conversion
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
116 # methods, like time related columns (e.g. +created_at+, +updated_at+).
4db718e @NZKoz Only cache attributes which need it for performance reasons. Closes #…
NZKoz authored
117 def cache_attributes(*attribute_names)
118 attribute_names.each {|attr| cached_attributes << attr.to_s}
119 end
120
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
121 # Returns the attributes which are cached. By default time related columns
122 # with datatype <tt>:datetime, :timestamp, :time, :date</tt> are cached.
4db718e @NZKoz Only cache attributes which need it for performance reasons. Closes #…
NZKoz authored
123 def cached_attributes
124 @cached_attributes ||=
125 columns.select{|c| attribute_types_cached_by_default.include?(c.type)}.map(&:name).to_set
126 end
127
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
128 # Returns +true+ if the provided attribute is being cached.
4db718e @NZKoz Only cache attributes which need it for performance reasons. Closes #…
NZKoz authored
129 def cache_attribute?(attr_name)
130 cached_attributes.include?(attr_name)
131 end
132
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
133 private
134 # Suffixes a, ?, c become regexp /(a|\?|c)$/
135 def rebuild_attribute_method_regexp
136 suffixes = attribute_method_suffixes.map { |s| Regexp.escape(s) }
137 @@attribute_method_regexp = /(#{suffixes.join('|')})$/.freeze
138 end
139
140 # Default to =, ?, _before_type_cast
141 def attribute_method_suffixes
142 @@attribute_method_suffixes ||= []
143 end
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
144
72385a7 @technoweenie Add Time Zone support to ActiveRecord, and config.time_zone property …
technoweenie authored
145 def create_time_zone_conversion_attribute?(name, column)
146 time_zone_aware_attributes && !skip_time_zone_conversion_for_attributes.include?(name.to_sym) && [:datetime, :timestamp].include?(column.type)
147 end
148
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
149 # Define an attribute reader method. Cope with nil column.
150 def define_read_method(symbol, attr_name, column)
151 cast_code = column.type_cast_code('v') if column
152 access_code = cast_code ? "(v=@attributes['#{attr_name}']) && #{cast_code}" : "@attributes['#{attr_name}']"
153
154 unless attr_name.to_s == self.primary_key.to_s
155 access_code = access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless @attributes.has_key?('#{attr_name}'); ")
156 end
157
4db718e @NZKoz Only cache attributes which need it for performance reasons. Closes #…
NZKoz authored
158 if cache_attribute?(attr_name)
159 access_code = "@attributes_cache['#{attr_name}'] ||= (#{access_code})"
160 end
161 evaluate_attribute_method attr_name, "def #{symbol}; #{access_code}; end"
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
162 end
163
164 # Define read method for serialized attribute.
165 def define_read_method_for_serialized_attribute(attr_name)
166 evaluate_attribute_method attr_name, "def #{attr_name}; unserialize_attribute('#{attr_name}'); end"
167 end
72385a7 @technoweenie Add Time Zone support to ActiveRecord, and config.time_zone property …
technoweenie authored
168
98dc582 @lifo Merge docrails.
lifo authored
169 # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled.
170 # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone.
72385a7 @technoweenie Add Time Zone support to ActiveRecord, and config.time_zone property …
technoweenie authored
171 def define_read_method_for_time_zone_conversion(attr_name)
172 method_body = <<-EOV
173 def #{attr_name}(reload = false)
174 cached = @attributes_cache['#{attr_name}']
175 return cached if cached && !reload
176 time = read_attribute('#{attr_name}')
54ccdd3 @gbuesing Time, DateTime and TimeWithZone #in_time_zone defaults to Time.zone. …
gbuesing authored
177 @attributes_cache['#{attr_name}'] = time.acts_like?(:time) ? time.in_time_zone : time
72385a7 @technoweenie Add Time Zone support to ActiveRecord, and config.time_zone property …
technoweenie authored
178 end
179 EOV
180 evaluate_attribute_method attr_name, method_body
181 end
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
182
98dc582 @lifo Merge docrails.
lifo authored
183 # Defines a predicate method <tt>attr_name?</tt>.
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
184 def define_question_method(attr_name)
185 evaluate_attribute_method attr_name, "def #{attr_name}?; query_attribute('#{attr_name}'); end", "#{attr_name}?"
186 end
187
188 def define_write_method(attr_name)
189 evaluate_attribute_method attr_name, "def #{attr_name}=(new_value);write_attribute('#{attr_name}', new_value);end", "#{attr_name}="
190 end
72385a7 @technoweenie Add Time Zone support to ActiveRecord, and config.time_zone property …
technoweenie authored
191
98dc582 @lifo Merge docrails.
lifo authored
192 # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled.
c1c1d6c @gbuesing Adding documentation for time zone features
gbuesing authored
193 # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone.
72385a7 @technoweenie Add Time Zone support to ActiveRecord, and config.time_zone property …
technoweenie authored
194 def define_write_method_for_time_zone_conversion(attr_name)
195 method_body = <<-EOV
196 def #{attr_name}=(time)
06a7c29 @gbuesing Time.zone.parse: return nil for strings with no date information
gbuesing authored
197 unless time.acts_like?(:time)
328fada @gbuesing ActiveRecord time zone aware attributes: blank string is treated as n…
gbuesing authored
198 time = time.is_a?(String) ? Time.zone.parse(time) : time.to_time rescue time
72385a7 @technoweenie Add Time Zone support to ActiveRecord, and config.time_zone property …
technoweenie authored
199 end
328fada @gbuesing ActiveRecord time zone aware attributes: blank string is treated as n…
gbuesing authored
200 time = time.in_time_zone rescue nil if time
72385a7 @technoweenie Add Time Zone support to ActiveRecord, and config.time_zone property …
technoweenie authored
201 write_attribute(:#{attr_name}, time)
202 end
203 EOV
204 evaluate_attribute_method attr_name, method_body, "#{attr_name}="
205 end
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
206
207 # Evaluate the definition for an attribute related method
208 def evaluate_attribute_method(attr_name, method_definition, method_name=attr_name)
209
210 unless method_name.to_s == primary_key.to_s
211 generated_methods << method_name
212 end
213
214 begin
cff25aa @jeremy eval with __FILE__ and __LINE__
jeremy authored
215 class_eval(method_definition, __FILE__, __LINE__)
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
216 rescue SyntaxError => err
217 generated_methods.delete(attr_name)
218 if logger
219 logger.warn "Exception occurred during reader method compilation."
220 logger.warn "Maybe #{attr_name} is not a valid Ruby identifier?"
4d092ba @clemens Some performance goodness for AR.
clemens authored
221 logger.warn err.message
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
222 end
223 end
224 end
225 end # ClassMethods
226
227
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
228 # Allows access to the object attributes, which are held in the <tt>@attributes</tt> hash, as though they
0faa4ca @dhh Doc fix (closes #9323) [Henrik N]
dhh authored
229 # were first-class methods. So a Person class with a name attribute can use Person#name and
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
230 # Person#name= and never directly use the attributes hash -- except for multiple assigns with
231 # ActiveRecord#attributes=. A Milestone class can also ask Milestone#completed? to test that
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
232 # the completed attribute is not +nil+ or 0.
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
233 #
234 # It's also possible to instantiate related objects, so a Client class belonging to the clients
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
235 # table with a +master_id+ foreign key can instantiate master through Client#master.
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
236 def method_missing(method_id, *args, &block)
237 method_name = method_id.to_s
238
4d9a7ab Changed ActiveRecord attributes to respect access control.
Adam Milligan authored
239 if self.class.private_method_defined?(method_name)
5c97d4f @ffmike "raise NoMethodError" raises NoMethodError. Raise it with NoMethodErr…
ffmike authored
240 raise NoMethodError.new("Attempt to call private method", method_name, args)
4d9a7ab Changed ActiveRecord attributes to respect access control.
Adam Milligan authored
241 end
242
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
243 # If we haven't generated any methods yet, generate them, then
244 # see if we've created the method we're looking for.
245 if !self.class.generated_methods?
246 self.class.define_attribute_methods
247 if self.class.generated_methods.include?(method_name)
248 return self.send(method_id, *args, &block)
249 end
250 end
251
252 if self.class.primary_key.to_s == method_name
253 id
254 elsif md = self.class.match_attribute_method?(method_name)
255 attribute_name, method_type = md.pre_match, md.to_s
256 if @attributes.include?(attribute_name)
257 __send__("attribute#{method_type}", attribute_name, *args, &block)
258 else
259 super
260 end
261 elsif @attributes.include?(method_name)
262 read_attribute(method_name)
263 else
264 super
265 end
266 end
267
268 # Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
269 # "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).
270 def read_attribute(attr_name)
271 attr_name = attr_name.to_s
272 if !(value = @attributes[attr_name]).nil?
273 if column = column_for_attribute(attr_name)
274 if unserializable_attribute?(attr_name, column)
275 unserialize_attribute(attr_name)
276 else
277 column.type_cast(value)
278 end
279 else
280 value
281 end
282 else
283 nil
284 end
285 end
286
287 def read_attribute_before_type_cast(attr_name)
288 @attributes[attr_name]
289 end
290
291 # Returns true if the attribute is of a text column and marked for serialization.
292 def unserializable_attribute?(attr_name, column)
293 column.text? && self.class.serialized_attributes[attr_name]
294 end
295
296 # Returns the unserialized object of the attribute.
297 def unserialize_attribute(attr_name)
298 unserialized_object = object_from_yaml(@attributes[attr_name])
299
300 if unserialized_object.is_a?(self.class.serialized_attributes[attr_name]) || unserialized_object.nil?
51977bc @technoweenie Fix bug where unserializing an attribute attempts to modify a frozen …
technoweenie authored
301 @attributes.frozen? ? unserialized_object : @attributes[attr_name] = unserialized_object
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
302 else
303 raise SerializationTypeMismatch,
304 "#{attr_name} was supposed to be a #{self.class.serialized_attributes[attr_name]}, but was a #{unserialized_object.class.to_s}"
305 end
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
306 end
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
307
308
309 # Updates the attribute identified by <tt>attr_name</tt> with the specified +value+. Empty strings for fixnum and float
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
310 # columns are turned into +nil+.
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
311 def write_attribute(attr_name, value)
312 attr_name = attr_name.to_s
313 @attributes_cache.delete(attr_name)
314 if (column = column_for_attribute(attr_name)) && column.number?
315 @attributes[attr_name] = convert_number_column_value(value)
316 else
317 @attributes[attr_name] = value
318 end
319 end
320
321
322 def query_attribute(attr_name)
323 unless value = read_attribute(attr_name)
324 false
325 else
326 column = self.class.columns_hash[attr_name]
327 if column.nil?
328 if Numeric === value || value !~ /[^0-9]/
329 !value.to_i.zero?
330 else
1fe9d6c @maxlapshin Support true/false in query_attribute for calculated columns
maxlapshin authored
331 return false if ActiveRecord::ConnectionAdapters::Column::FALSE_VALUES.include?(value)
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
332 !value.blank?
333 end
334 elsif column.number?
335 !value.zero?
336 else
337 !value.blank?
338 end
339 end
340 end
341
1646e8c @clemens More symbols for send and respond_to?.
clemens authored
342 # A Person object with a name attribute can ask <tt>person.respond_to?(:name)</tt>,
343 # <tt>person.respond_to?(:name=)</tt>, and <tt>person.respond_to?(:name?)</tt>
46f30f9 @lifo Merge documentation changes from docrails.
lifo authored
344 # which will all return +true+.
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
345 alias :respond_to_without_attributes? :respond_to?
4d9a7ab Changed ActiveRecord attributes to respect access control.
Adam Milligan authored
346 def respond_to?(method, include_private_methods = false)
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
347 method_name = method.to_s
348 if super
349 return true
f550c86 @alk Fix performance bug in AttibuteMethods#respond_to? in handling of pri…
alk authored
350 elsif !include_private_methods && super(method, true)
351 # If we're here than we haven't found among non-private methods
352 # but found among all methods. Which means that given method is private.
4d9a7ab Changed ActiveRecord attributes to respect access control.
Adam Milligan authored
353 return false
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
354 elsif !self.class.generated_methods?
355 self.class.define_attribute_methods
356 if self.class.generated_methods.include?(method_name)
357 return true
358 end
359 end
360
361 if @attributes.nil?
362 return super
363 elsif @attributes.include?(method_name)
364 return true
365 elsif md = self.class.match_attribute_method?(method_name)
366 return true if @attributes.include?(md.pre_match)
367 end
368 super
369 end
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
370
371 private
5b801b5 @NZKoz Change the implementation of ActiveRecord's attribute reader and writ…
NZKoz authored
372
373 def missing_attribute(attr_name, stack)
374 raise ActiveRecord::MissingAttributeError, "missing attribute: #{attr_name}", stack
375 end
376
2b3cc24 @jeremy r4854@ks: jeremy | 2006-07-30 00:59:18 -0700
jeremy authored
377 # Handle *? for method_missing.
378 def attribute?(attribute_name)
379 query_attribute(attribute_name)
380 end
381
382 # Handle *= for method_missing.
383 def attribute=(attribute_name, value)
384 write_attribute(attribute_name, value)
385 end
386
387 # Handle *_before_type_cast for method_missing.
388 def attribute_before_type_cast(attribute_name)
389 read_attribute_before_type_cast(attribute_name)
390 end
391 end
392 end
Something went wrong with that request. Please try again.