Corey Innis's blog



Corey InnisCorey Innis
Standup 05/30/2008
edit Posted by Corey Innis on Friday May 30, 2008 at 06:25PM

Interesting Things

  • ActiveRecord's #method_missing takes precedence over private methods, which means you cannot simply mark "private" database-derived attributes.
    code:

    # File: app/models/rock_star.rb
    #
    # == Schema Information
    # Schema version: 1
    #
    # Table name: rock_stars
    #
    #  id            :integer         not null, primary key
    #  real_name     :string(255)     
    #  band_name     :string(255)     
    #  personal_life :string(255)     
    #
    
    
    class RockStar < ActiveRecord::Base
      def method_missing(method, *arguments, &block)
        puts "I see you've sent my #{method} back and my ActiveRecords and they're all scratched"
        super
      end
    
    
      private
    
    
      def personal_life=(arg)
        puts "Vanish in the air you'll never find me"
        attributes[:personal_life] = arg
      end
    end
    

    script/console:

    Loading development environment (Rails 2.0.2)
    >> sting = RockStar.new(:real_name => 'Gordon Sumner', :band_name => 'The Police')
    I see you've sent my real_name= back and my ActiveRecords and they're all scratched
    => #<RockStar id: nil, real_name: "Gordon Sumner", band_name: "The Police", personal_life: nil>
    >> sting.personal_life = "I'll be watching you"
    I see you've sent my personal_life= back and my ActiveRecords and they're all scratched
    => "I'll be watching you"
    

    Potential solutions:

    • Convention... name "private" database attributes with leading underscores
    • Exception:

      class RockStar < ActiveRecord::Base
        def personal_life=(arg)
          raise "Protest is futile, nothing seems to get through"
        end
      end
      
    • Have another? Post a comment.

  • ||= ("or equal") blows up you have a public "writer", but a private "reader"; makes sense, but still worth a mention.
    code:

    class Model < ActiveRecord::Base
      def field_name=(arg)
        @field_name = arg
      end
    
    
      private
    
    
      def field_name
        @field_name
      end
    end
    

    script/console:

    Loading development environment (Rails 2.0.2)
    >> instance = Model.new
    => #<Model id: nil, field_name: nil>
    >> instance.field_name = 'lala'
    => "lala"
    >> instance.field_name ||= 'dodo'
    NoMethodError: private method `field_name' called for #<Model:0x17df6d0>
      from /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/attribute_methods.rb:205:in `method_missing'
      from (irb):4
    
  • ActiveRecord writers always return the passed in argument, even if you define some other return value. This also makes sense -- necessary for chaining, etc., but what the heck...
    code:

    class Model < ActiveRecord::Base
      def field_name=(arg)
        @field_name = arg            
        return "custom return value"
      end
    end
    

    script/console:

    Loading development environment (Rails 2.0.2)
    >> instance = Model.new
    => #<Model id: nil, field_name: nil>
    >> instance.field_name = 'lala'
    => "lala"