Hi Jeremy, Yes, the Sequel is doing a good job for that edge case. So in AR `super` makes method_missing to define the `ghost` attribute method `name` in order to reduce the method lookup next time. After it gets defined it also calls that method - at that time it should only return "bob". After it gets called in method_missing, shouldn't it just return back into our User#name scope? Since the second time we call User#name we get the expected result, we can assume that method_missing defined the `ghost` attribute correctly. Right? But it is still not very clear to me why the 'Hi' gets capitalized. I would expect 'bob' to be repeated twice if we have the case of doubled method call. # Smth. like this: 'hi Bob bob'
BTW, I found this investigation interesting and I'd like to summarize it into a small article (I've started it here: https://gist.github.com/930514). Would you like to participate? -- Thanks On Apr 27, 9:09 am, Jeremy Evans <[email protected]> wrote: > On Tue, Apr 26, 2011 at 4:44 PM, ivanpoval <[email protected]> wrote: > > Hi, here is the example of the wrong usage of the `super` keyword > > trying to override the attribute method. > > > class User < ActiveRecord::Base > > def name > > super.to_s.capitalize > > end > > end > > > The result of this code looks 'pseudo'-correct and some people assume > > it's fine to use that like if it were self[:name].to_s.capitalize > > If we take a look at the code below - the results are different: > > > class User < ActiveRecord::Base > > def name > > 'hi ' + super.to_s.capitalize > > end > > end > > > u = User.first > > p u.name # => 'hi Hi bob' > > p u.name # => 'hi Bob' > > p u.name # => 'hi Bob' > > > My question is why the first call to u.name produces that result. > > I'm looking at > > if self.class.generated_methods.include?(method_name) > > return self.send(method_id, *args, &block) > > end > > > in > > module ActiveRecord > > module AttributeMethods > > def method_missing > > > but need some help to figure the things out. > > Simply want to know what is actually happening... > > The first time you call name, your super call actually calls > method_missing, since the name method doesn't exist higher in the > method chain. method_missing doesn't think the attribute methods have > been defined yet, so it calls a method to define them in an anonymous > module included in the class, then calls the method again. Basically, > the first time you call it: > > User#name -> ActiveRecord::AttributeMethods#method_missing -> > User#name -> generated_methods_module#name > > Future calls don't hit method_missing because > generated_methods_module#name already exists: > > User#name -> generated_methods_module#name > > Your example works fine in Sequel, BTW, because Sequel sets up the > attribute methods in an anonymous module included in the class at > class definition time, instead of when the attribute method is first > called. I wouldn't be surprised if the ActiveRecord way of defining > attribute methods is subject to a race condition in threaded code, in > addition to the problem you are experiencing. > > Jeremy -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
