Reputation: 2130
I'm writing my first rails plugin and could use a little help. In a very simplified way, I'd like to do allow the developer to specify a value which I can count through a rake task. I'm thinking of something like this...
class User < ActiveRecord::Base
monitor "Users", count
monitor "Active Users", count("activated_at != NULL")
end
monitor
function shouldn't be the value but a block of code to execute. I'm not quite sure of the best way to specify this and keep the syntax simple. Perhaps it'll have to be monitor "Active Users", {count "activated_at != NULL"}
?User.count
, just count
, i.e. it would pick up the Class automatically (and the blocks will be called on the class not the instance). If this isn't possible, I guess there's no reason to put the monitor statements into the model (see #5).monitor
function do to make these blocks available to the rake task? Store them in a class variable?I'm just sketching out my ideas at the moment and trying to figure out what is/isn't possible in Ruby. Any help appreciated.
Update: I'll try to be clearer on the plugin's purpose. I want the developer to be able to define metrics which should be monitored by the rake task. The rake task will iterate over those metrics and write the values to a file (I've simplified this a bit). The rake task will be very simple, something like rake monitors:update
(i.e., no params required)
Upvotes: 2
Views: 1098
Reputation: 2130
Thanks for all your help, however I went with a different approach (extracted below).
Instead of specifying the attributes in the models, I used an approach seen in the whenever gem. I placed a ruby file "dashboard.rb" in my config directory:
dashboard "Users", User.count
dashboard "Activated Users", User.count('activated_at')
My lib consists of two functions:
def self.dashboard(name, attribute)
puts "** dailydashboard: #{name} = #{attribute.to_s}"
end
def self.update(file)
eval File.read(file)
end
Basically, my rake task calls update
, which loads dashboard.rb
and eval
uates it and repeatedly calls the dashboard
function, which outputs this:
** dailydashboard: Users = 2
** dailydashboard: Activated Users = 1
Sorry for going around the houses a little bit. For background/offline things this seems like a very simple approach and does what I need. Thanks for your help though!
Upvotes: 0
Reputation: 2947
Something like this should do what you want:
module Monitored
@@monitors = []
def self.monitor(name, method)
@@monitors.push [name, method]
end
def self.run_monitor(name)
send @@monitors.select{|m| m[0] == name}[0][1]
end
end
Untested, but you get the idea, I hope.
Upvotes: 0
Reputation: 74985
You are probably putting the definition of the rake tasks in the wrong place. The model should only contain logic that is valid for any of its consumers, and not concern itself with specific applications like rake.
A better approach may be to define some named scopes in your models, and specify the actions you wish to be available in your rake tasks. The named scopes can be reused easily in other areas of your application. A model may look like this (note that this is a Rails feature -- no work required on your part):
class User < ActiveRecord::Base
named_scope :active_users, :conditions => "activated_at != NULL"
end
And then you would create a very simple DSL that can be used within rake files (e.g. in lib/tasks/count.rake
). Something that will allow you to do this, for example:
require "your-plugin"
namespace :count do
# Make your plugin rewrite this internally to User.count
YourPlugin::CountTask.new :users
# Make your plugin rewrite this to User.active_users.count
YourPlugin::CountTask.new :users, :active_users
# Perhaps allow usage of blocks as well?
YourPlugin::CountTask.new :users, :complicated do
User.count(complex_conditions)
end
end
This should then provide the user with tasks named count:users
, count:users:active_users
and count:users:complicated
.
Upvotes: 1
Reputation: 9093
Try looking at the code for named_scope
whats the design for the rake task looking like?
rake monitor:user:active_users ?
OT:
activated_at is not null
is the SQL that you want
Come to think of it, why not forget defining monitor, and just use named_scopes ? where instead of returning a select *
, you do a select count(*)
Upvotes: 0