Distinct Values
module ActiveRecord #mixin for active record module ModelHelper # module name def self.included(base) # include this into the base of the class instance base.class_eval do # evaluate the below (class << self;self;end).class_eval do def self.distinct_values(column) find(:all, :select => "DISTINCT #{column}").map{|x| x.send(column)} if column_names.include?(column) end end </a> end end end end
I like to setup a file in the /lib directory to hold model_helper.rb. I tend to put functions that I like to mix into all of my models into this file. This keeps things dry and it prevents me from running all over wondering where a certain active record model function is located.
def self.distinct_values(column) find(:all, :select => "DISTINCT #{column}").map{|x| x.send(column)} if column_names.include?(column) end
After I mix this function in to all the active records objects I’m give the ability to call it like this:
distinct_items = Model.distinct_values("column_name") #> ["value1","value2","value3"]
This will return distinct values of a model, instead of the objects themselves. I find this useful in projects where there is sometimes an intentional lack of normalization on a table.
table: posts +-----+----------+ | id | category | +-----+----------+ | 5 | ruby | | 35 | ruby | | 52 | news | | 53 | news | | 63 | news |
so now we can just call.
Post.distinct_values("category") #-> ["ruby","news"]
This is useful for filling dropdown lists, select boxes, etc.
March 15th, 2009 at 3:03 am
So by doing this:
def self.included(base) # include this into the base of the class instance
The method is defined in the parent class for all extending classes. And you can easily override / extend this method in all those extending classes?
March 15th, 2009 at 11:40 am
in the case of ActiveRecord module (its already being included). When I extend my ‘base’ which is the where this module is included. I believe in ActiveRecord::Base. Then all inherited classes and there instances receive this method.
March 16th, 2009 at 5:32 pm
ok, cool i think that answers my very vague question. By saying you “mix in” this method it means the base object has the method, so all other models can easily override or extend that method.
September 25th, 2009 at 12:55 am
Thanks for the post. Nice thoughts!
one question regarding this part of the code
(class < “DISTINCT #{column}”).map{|x| x.send(column)} if column_names.include?(column)
end
end
should it be without ’self.’ here? def distinct_values(column) … the eigen class of ActiveRecord would be Class#ActiveRecord. maybe I’m missing something?
September 25th, 2009 at 12:57 am
sorry for post again, it seems I forgot to format the code plz clean it up for me.
September 25th, 2009 at 12:11 pm
Without testing, I’m not entirely sure if it would work or not. However, I know it does work with self.distinct_values. I placed self. because this is a class method mixed into the ActiveRecord Class. All inheritied classes will now have this method. So this will allow Child <(of) ActiveRecord::Base to call distinct values.