Dr Nic

So, cattr_accessor doesn’t work like it should?

Rails’ active_support library adds some wonderful functions into standard Ruby classes. Some we all use day-in-day out are attr_accessor and its class-level equivalent, cattr_accessor.

But cattr_accessor doesn’t work the way you (read, “me”) thought at first glance when you use subclasses. I thought if I declared a class accessor in the superclass, then I would have independent class attributes for all my subclasses. Apparently not…

>> class Parent; cattr_accessor :val; end
=> [:val]
>> class Child1 < Parent; end
=> nil
>> class Child2 < Parent; end
=> nil
>> Child1.val = 4
=> 4
>> Child2.val
=> 4
>> Child2.val = 5
=> 5
>> Child1.val
=> 5

Child1.val and Child2.val seem to be the same value. Not very independent at all. Internally, the classes share a common class attribute. This is useful in certain circumstances, but not what I was looking for.

Instead, I found class_inheritable_accessor.

>> class Parent; class_inheritable_accessor :val; end
=> [:val]
>> class Child1 < Parent; end
=> nil
>> class Child2 < Parent; end
=> nil
>> Child1.val = 4
=> 4
>> Child2.val = 4
=> 4
>> Child2.val = 5
=> 5
>> Child1.val
=> 4

Lovely. Each subclass will have an independent value once you’ve assigned it a value explicitly, else it will pick up the value from its superclass.

UPDATE: class_inheritable_accessor and co. actually clone the superclass’s inherited attributes, rather than just referencing them.

Related posts:

  1. Magic Multi-Connections: A “facility in Rails to talk to more than one database at a time” At this point in time there’s no facility in Rails...
  2. Turn-based game DSL Late in the night, whilst the baby feeds, I continue...
  3. Extending _why’s Creature class Many Rubist’s first explanation of metaprogramming is by why the...
  4. [BTS] Magic Models vs ActiveRecords – Efficiency Dr Nic’s Magic Models are magical, that goes without saying....
  5. [BTS] Magic Models – Class creation [BTS] = Behind the Scenes; also a news-like TV show...

6 Responses to “So, cattr_accessor doesn’t work like it should?”

  1. choonkeat says:

    hmm, correction. attr_accessor comes from ruby, not from active_support.

  2. Dr Nic says:

    Yeah, sorry. cattr* and mattr* are added by rails.

  3. [...] There’s a bit of discussion this on a separate, but related problem at Evan Weaver’s blog (pay special attention to that threading issue for those playing along with the home game). And of course, your friendly neighborhood reminder of what happens with class variables at Nic Williams’ blog (I recommend reading that twice and breaking out the home game version of irb) [...]

  4. [...] 节选了部分代码,调用流程为process -> perform_action => action || method_missing || template || raise UnknownAction 其中需要注意的几点: 1,@@default_charset = “utf-8″ 2,attr_internal的属性有request、params、response、session、headers 3,cattr_accessor的属性有default_charset、logger、consider_all_requests_localç­‰ catter_accessor标识的是Class Attributes,见这篇BlogSo, cattr_accessor doesn’t work like it should? catter_accessor方法的定义在active_supportcore_extclassattribute_accessors.rb: 代码 class Class def cattr_reader(*syms) syms.flatten.each do |sym| next if sym.is_a?(Hash) class_eval(<< render_file 2):text -> render_text 3):file -> render_file 4):template -> render_file 5):inline -> render_template 6):action -> render_action 7):xml -> render_xml 8):json -> render_json 9):partial -> render_partial || render_partial_collection 10):update -> render_javascript 11):noting -> render_text 5,redirect_to方法的参数有: 1)Hash -> redirect_to(url_for(options)) [code] redirect_to :action => “show”, :id => 5 [...]

  5. Andy Goundry says:

    Wonderful post! Is the exact solution to my needs. I was (and still am) baffled that this stuff isn’t available in Ruby.

    Thanks!