Hi, Just trying to understand what "cattr_accessor" is in the acts_as_audited plugin. Any ideas? [In particular I''m trying to understand how to create the appropriate User class so I can turn on logging of userid - I''m using activeRBAC for authentication] Example usage: cattr_accessor :non_audited_columns, :audited_user_class_name, :audited_user_method Full extract from plugin (used within here): =================================================# Copyright (c) 2006 Brandon Keepers # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. module CollectiveIdea #:nodoc: module Acts #:nodoc: # Specify this act if you want changes to your model to be saved in an # audit table. This assumes there is an audits table ready. # # class User < ActiveRecord::Base # acts_as_audited # end # # See <tt>CollectiveIdea::Acts::Audited::ClassMethods#acts_as_audited</tt> # for configuration options module Audited CALLBACKS = [:clear_changed_attributes, :audit_create, :audit_update, :audit_destroy] def self.included(base) # :nodoc: base.extend ClassMethods end module ClassMethods # == Configuration options # # * <tt>except</tt> - Excludes fields from being saved in the audit log. # By default, acts_as_audited will audit all but these fields: # # [self.primary_key, inheritance_column, ''lock_version'', ''created_at'', ''updated_at''] # # You can add to those by passing one or an array of fields to skip. # # class User < ActiveRecord::Base # acts_as_audited :except => :password # end # # * <tt>user_class_name</tt> - specifiy the class name of the user class. # This defaults to "User". Set to false to disable user auditing. # # * <tt>user_method</tt> - specify the method to call on <tt>:user_class_name</tt> # that returns the user that is performing the action. This defaults to # <tt>:current_user</tt>. # # == Database Schema # def acts_as_audited(options = {}) # don''t allow multiple calls return if self.included_modules.include?(CollectiveIdea::Acts::Audited::InstanceMethods) include CollectiveIdea::Acts::Audited::InstanceMethods class_eval do extend CollectiveIdea::Acts::Audited::SingletonMethods cattr_accessor :non_audited_columns, :audited_user_class_name, :audited_user_method self.non_audited_columns = [self.primary_key, inheritance_column, ''lock_version'', ''created_at'', ''updated_at''] self.non_audited_columns |= options[:except].is_a?(Array) ? options[:except].collect{|column| column.to_s} : [options[:except].to_s] if options[:except] self.audited_user_class_name = options[:user_class_name].nil? ? "User" : options[:user_class_name] self.audited_user_method = options[:user_method] || :current_user has_many :audits, :as => :auditable after_create :audit_create after_update :audit_update before_destroy :audit_destroy after_save :clear_changed_attributes end end end module InstanceMethods # Temporarily turns off auditing while saving. def save_without_auditing without_auditing do save end end # Returns an array of attribute keys that are audited. See non_audited_columns def audited_attributes self.attributes.keys.select { |k| !self.class.non_audited_columns.include?(k) } end # If called with no parameters, gets whether the current model has changed. # If called with a single parameter, gets whether the parameter has changed. def changed?(attr_name = nil) attr_name.nil? ? (@changed_attributes && @changed_attributes.length > 0) : (@changed_attributes && @changed_attributes.include?(attr_name.to_s)) end # Executes the block with the auditing callbacks disabled. # # @foo.without_auditing do # @foo.save # end # def without_auditing(&block) self.class.without_auditing(&block) end private # Creates a new record in the audits table if applicable def audit_create logger.debug "ACTS AS: audit_create" write_audit(:create) end def audit_update write_audit(:update) if changed? end def audit_destroy write_audit(:destroy) end def write_audit(action = :update) logger.debug "ACTS AS: write_audit" logger.debug "ACTS AS: self.audited_user_class_name = #{self.audited_user_class_name}" #logger.debug "ACTS AS: Object.const_get(audited_user_class_name) = #{Object.const_get(audited_user_class_name)}" logger.debug "ACTS AS: self.audited_user_method = #{self.audited_user_method}" user = self.audited_user_class_name ? Object.const_get(audited_user_class_name).send(self.audited_user_method) : nil logger.debug "ACTS AS: user = #{user}" audits.create(:changes => @changed_attributes, :action => action.to_s, :user_id => user ? user.id : nil) end # clears current changed attributes. Called after save. def clear_changed_attributes @changed_attributes = {} end # overload write_attribute to save changes to audited attributes def write_attribute(attr_name, attr_value) attr_name = attr_name.to_s if audited_attributes.include?(attr_name) @changed_attributes ||= {} # get original value old_value = @changed_attributes[attr_name] ? @changed_attributes[attr_name].first : self[attr_name] super(attr_name, attr_value) new_value = self[attr_name] @changed_attributes[attr_name] = [old_value, new_value] if new_value != old_value else super(attr_name, attr_value) end end CALLBACKS.each do |attr_name| alias_method "orig_#{attr_name}".to_sym, attr_name end def empty_callback() end #:nodoc: end # InstanceMethods module SingletonMethods # Returns an array of columns that are audited. See non_audited_columns def audited_columns self.columns.select { |c| !non_audited_columns.include?(c.name) } end # Executes the block with the auditing callbacks disabled. # # Foo.without_auditing do # @foo.save # end # def without_auditing(&block) class_eval do CALLBACKS.each do |attr_name| alias_method attr_name, :empty_callback end end result = block.call class_eval do CALLBACKS.each do |attr_name| alias_method attr_name, "orig_#{attr_name}".to_sym end end result end end end end end ActiveRecord::Base.send :include, CollectiveIdea::Acts::Audited ================================================= -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
Hi Greg, On Sep 4, 2006, at 12:34 AM, Greg Hauptmann wrote:> Just trying to understand what "cattr_accessor" is in the > acts_as_audited plugin. Any ideas?Check out activesupport/lib/active_support/core_ext/class/attribute_accessors.rb You can think of cattr_accessor as an attr_accessor for a class (thus the ''c''), instead of for an instance of a class. Essentially, it''s a little sugar to make life easier when giving classes read/write attributes. (Not that such things are difficult in Ruby proper.) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
Had a quick look at this (e.g. cattr_reader - extract below) - still I little unclear to me. Do you think you could run what "cattr_accessor" does in layman''s terms at all? e.g. difference between class & instant aspects. (sorry - the penny hasn''t dropped yet :) ) ================ def cattr_reader(*syms) syms.flatten.each do |sym| class_eval(<<-EOS, __FILE__, __LINE__) unless defined? @@#{sym} @@#{sym} = nil end def self.#{sym} @@#{sym} end def #{sym} @@#{sym} end EOS end end ==================== --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
class Songs @@play_count = 0 def self.play_count # The cattr_reader thang @@play_count end def play @@play_count += 1 end end song1 = Songs.new song1.play> 1song2 = Songs.new song2.play> 2Songs.play_count> 2Hope that helps. On 04/09/06, Greg H <greg.hauptmann.ruby-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > Had a quick look at this (e.g. cattr_reader - extract below) - still I > little unclear to me. Do you think you could run what "cattr_accessor" does > in layman''s terms at all? e.g. difference between class & instant > aspects. (sorry - the penny hasn''t dropped yet :) ) > > ================> def cattr_reader(*syms) > syms.flatten.each do |sym| > class_eval(<<-EOS, __FILE__, __LINE__) > unless defined? @@#{sym} > @@#{sym} = nil > end > > def self.#{sym} > @@#{sym} > end > > def #{sym} > @@#{sym} > end > EOS > end > end > ====================> > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
thanks Ian - I think I got it - just have to go back and make sense of this within the code that was also doing multiple modules / includes / and extends :) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
dblack-TKXtfPMJ4Ozk1uMJSBkQmQ@public.gmane.org
2006-Sep-04 11:39 UTC
Re: what is "cattr_accessor" (used in acts_as_audited)
Hi -- On Mon, 4 Sep 2006, Greg H wrote:> Had a quick look at this (e.g. cattr_reader - extract below) - still I > little unclear to me. Do you think you could run what "cattr_accessor" does > in layman''s terms at all? e.g. difference between class & instant > aspects. (sorry - the penny hasn''t dropped yet :) )In layman''s terms, I''d describe it as, "A computer programming thing" :-) But here''s a somewhat super-layman explanation. Ruby has an attr_* family of methods: class C attr_accessor :x attr_reader :y attr_writer :z end These attr_* methods are meta-methods; that is, calling them actually results in the automatic creation of other methods. In the example above, instances of C will have the following methods: x # reader x= # writer y # reader z= # writer The idea is to provide a convenient way to get and/or set state in an object: c = C.new c.x = 1 # actually a call to the x= method! puts c.x # a call to the x method The way this works is that the reader and writer methods (x, x=, etc.) store/retrieve values in/from instance variables. If you wrote them out, the methods that the attr_* methods create for you would look like this: class C def x # read "attribute" (i.e., value of instance variable) @x end def x=(value) # set "attribute" (i.e., set instance variable) @x = value end def y @y end def z=(value) @z = value end end In addition to instance variables, Ruby has class variables. The purpose of the cattr_* methods is to provide a mechanism exactly like the above -- but using class variables instead of instance variables. Furthermore, the set/get operations are available both to instances of the class, and to the class itself: class D cattr_accessor :a end d = D.new d.a = 1 # set via an instance puts D.a # get via the class So it''s just a kind of elaboration of the original Ruby attribute implementation. To get both the class and its instances to know about the get and set methods, there have to be two of each. So this is what the expanded version of the last example looks like: class D def self.a # class get method @@a end def self.a=(value) # class set method @@a = value end def a # instance get method @@a end def a=(value) # instance set method @@a = value end end I personally consider "cattr" (class attribute) a misnomer. "Attribute" suggests a property of an object. Class variables do not map onto the state of any particular object; they are visible to a given class, all of its subclasses, and all of the instances of itself and those subclasses. So when you save a value in a class variable, it''s a considerable stretch to refer to it as an "attribute". But anyway, the above is how it works and what it does. David -- David A. Black | dblack-TKXtfPMJ4Ozk1uMJSBkQmQ@public.gmane.org Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3] DABlog (DAB''s Weblog) [2] | Co-director, Ruby Central, Inc. [4] [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---
In ruby core programs "cattr_accessor" method is not recognized (it says undefined method `cattr_accessor''). I think you mean to say this method is available only in Rails, right? example program - class Kcattr cattr_accessor :var @@var = 10 end -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Kevin Skoglund
2007-Dec-20 16:03 UTC
Re: what is "cattr_accessor" (used in acts_as_audited)
Yes, it is only in Rails. /activesupport/lib/active_support/core_ext/class/ attribute_accessors.rb It is set as "nodoc" though, so the definitions don''t show up in the API. (Any reason not to change that?) Kevin http://www.nullislove.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
David - thank you for taking the time to write down this explanation. Helped me understand things. 3 years late but all the same. Shaun David Black wrote:> > In layman''s terms, I''d describe it as, "A computer programming thing" > :-) But here''s a somewhat super-layman explanation. > > Ruby has an attr_* family of methods: > > class C > attr_accessor :x > attr_reader :y > attr_writer :z > end >-- Posted via http://www.ruby-forum.com/.