为Rails编写ActiveRecord插件

时间:2009-07-08 09:44:11

标签: ruby-on-rails ruby activerecord plugins

我正在编写我的第一个rails插件,可以使用一些帮助。以非常简单的方式,我想让开发人员指定一个我可以通过rake任务计算的值。我在考虑这样的事情......

class User < ActiveRecord::Base
    monitor "Users", count
    monitor "Active Users", count("activated_at != NULL")
end
  1. 我想监视器需要是ActiveRecord :: Base的类方法,但我在插件中如何/在何处指定它?
  2. monitor函数的参数不应该是值,而是要执行的代码块。我不太确定指定它的最佳方法并保持语法简单。也许它必须是monitor "Active Users", {count "activated_at != NULL"}
  3. 我更喜欢开发人员不必指定User.count,只需count,即它会自动获取类(并且将在类上调用块而不是实例)。如果这是不可能的,我想没有理由将监控语句放入模型中(参见#5)。
  4. 这些值的实际计数(即块的执行)将通过离线的rake任务完成。 monitor函数应该如何使这些块可用于rake任务?将它们存储在类变量中?
  5. 可能根本不需要在模型中指定监视器语句。也许它会让它变得杂乱无章,所以我欢迎任何其他地方放置它们。
  6. 我现在只是草拟我的想法并试图找出Ruby中可能/不可能的内容。任何帮助表示赞赏。

    更新:我会尝试更清楚插件的用途。我希望开发人员能够定义应该由rake任务监控的指标。 rake任务将迭代这些指标并将值写入文件(我已经简化了一点)。 rake任务非常简单,例如rake monitors:update(即不需要参数)

4 个答案:

答案 0 :(得分:1)

您可能将rake任务的定义放在了错误的位置。该模型应该只包含对其任何消费者有效的逻辑,而不关心像rake这样的特定应用程序。

更好的方法可能是在模型中定义一些命名范围,并指定您希望在rake任务中可用的操作。命名范围可以在应用程序的其他区域轻松重用。模型可能如下所示(请注意,这是一个Rails功能 - 您无需工作):

class User < ActiveRecord::Base
  named_scope :active_users, :conditions => "activated_at != NULL"
end

然后你会创建一个非常简单的DSL,可以在rake文件中使用(例如在lib/tasks/count.rake中)。允许你这样做的东西,例如:

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

然后,应该为用户提供名为count:userscount:users:active_userscount:users:complicated的任务。

答案 1 :(得分:0)

尝试查看named_scope的代码

rake任务的设计是什么样的?

rake monitor:user:active_users?

OT:

activated_at is not null是您想要的SQL

想一想,为什么不忘记定义监视器,只使用named_scopes?而不是返回select *,而是select count(*)

答案 2 :(得分:0)

这样的事情应该做你想做的事情:

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

未经测试,但我希望你明白这一点。

答案 3 :(得分:0)

感谢您的所有帮助,但我采用了不同的方法(摘录如下)。

我没有在模型中指定属性,而是使用了随时随地看到的方法。我在配置目录中放置了一个ruby文件“dashboard.rb”:

dashboard "Users", User.count
dashboard "Activated Users", User.count('activated_at')

我的lib包含两个函数:

  def self.dashboard(name, attribute)
      puts "** dailydashboard: #{name} = #{attribute.to_s}"
  end

  def self.update(file)
    eval File.read(file)
  end

基本上,我的rake任务调用update,它会加载dashboard.rbeval,并重复调用dashboard函数,该函数输出:

** dailydashboard: Users = 2
** dailydashboard: Activated Users = 1

对不起,你可以到处走走一些房子。对于背景/离线事物,这似乎是一种非常简单的方法,并且做我需要的。谢谢你的帮助!