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