I’ve looked everywhere for an elegant solution. The essential problem seems to be that ActiveRecord attributes that map to database columns are handled completely differently in ActiveRecord::Base than attr_accessor methods.
I would like to do something like:
model.attribute_names.each do |name|
# do stuff
end
in a way that also includes attr_accessor fields, but not any other instance methods. I know this in not built-in, but what is the most elegant way to do it?
You can’t really solve this. You can approximate a hack, but it’s not something that will ever work nicely.
model.attribute_namesshould get you all the ActiveRecord ones, but theattr_accessorfields are not fields. They are just ordinary ruby methods, and the only way to get them is withmodel.instance_methods.Idea 1
You could do
model.attribute_names + model.instance_methods, but then you’d have to filter out all your other normal ruby methodsinitialize, save, etc which would be impractical.To help filter the
instance_methodsyou could match them up againstmodel.instance_variables(you’d have to account for the@sign in the instance variables manually), but the problem with this is that instance variables don’t actually exist at all until they are first assigned.Idea 2
In your
environment.rb, before anything else ever gets loaded, define your ownself.attr_accessorinActiveRecord::Base. This could then wrap the underlyingattr_accessorbut also save the attribute names to a private list. Then you’d be able to pull out of this list later on. However I’d advise against this… monkey-patching core language facilities likeattr_accessoris guaranteed to bring you a lot of pain.Idea 3
Define your own
custom_attr_accessorinActiveRecord::Base, which does the same thing as Idea 2, and use it in your code where you want to be able to retrieve the attribute names. This would be safe as you won’t be clobbering the built-inattr_accessormethod any more, but you’ll have to change all your code to usecustom_attr_accessorwhere neccessaryI guess in summary, what are you trying to do that needs to know about all the
attr_accessorfields? Try look at your problem from a different angle if you can.