当前位置:  开发笔记 > 后端 > 正文

如何实现单例模型

如何解决《如何实现单例模型》经验,为你挑选了5个好方法。

我在rails中有一个站点,并希望在站点范围内进行设置.如果发生特定事件,我的应用程序的一部分可以通过SMS通知管理员.这是我希望通过站点范围设置进行配置的功能示例.

所以我在想我应该有一个环境模型或类似的东西.它需要是一个模型,因为我希望能够使用has_many:SMS通知的联系人.

问题是数据库中只能有一个用于设置模型的帖子.所以我在考虑使用Singleton模型,但这只会阻止创建新对象吗?

我还需要为每个属性创建getter和setter方法,如下所示:

def self.attribute=(param)
  Model.first.attribute = param
end

def self.attribute
  Model.first.attribute
end

直接使用Model.attribute可能不是最佳实践,但总是创建它的实例并使用它吗?

我该怎么办?



1> Rich..:

(我同意@ user43685并且不同意@Derek P - 有很多理由将网站范围内的数据保存在数据库而不是yaml文件中.例如:您的设置将在所有Web服务器上可用(如果您有多个Web服务器);对您的设置的更改将是ACID;您不必花时间实现YAML包装等.)

在rails中,这很容易实现,你只需要记住你的模型应该是数据库术语中的"单例",而不是ruby对象术语.

实现这个的最简单方法是:

    添加一个新模型,为您需要的每个属性添加一列

    添加一个名为"singleton_guard"的特殊列,并验证它始终等于"0",并将其标记为唯一(这将强制该数据库中只有一行用于此表)

    向模型类添加静态辅助方法以加载单行

因此迁移应该如下所示:

create_table :app_settings do |t|
  t.integer  :singleton_guard
  t.datetime :config_property1
  t.datetime :config_property2
  ...

  t.timestamps
end
add_index(:app_settings, :singleton_guard, :unique => true)

模型类看起来应该是这样的:

class AppSettings < ActiveRecord::Base
  # The "singleton_guard" column is a unique column which must always be set to '0'
  # This ensures that only one AppSettings row is created
  validates_inclusion_of :singleton_guard, :in => [0]

  def self.instance
    # there will be only one row, and its ID must be '1'
    begin
      find(1)
    rescue ActiveRecord::RecordNotFound
      # slight race condition here, but it will only happen once
      row = AppSettings.new
      row.singleton_guard = 0
      row.save!
      row
    end
  end
end

在Rails> = 3.2.1中,您应该能够通过调用" first_or_create! " 来替换"instance"getter的主体,如下所示:

def self.instance
  first_or_create!(singleton_guard: 0)
end


如果它可以节省几分钟的时间,我建议不要使用名为"Config"的模型:http://oldwiki.rubyonrails.org/rails/pages/ReservedWords
那些保留的话每次都会得到你!

2> user43685..:

我不同意共同意见 - 从数据库中读取属性没有任何问题.如果您愿意,可以读取数据库值并冻结,但是可以有更灵活的替代方法来简单冻结.

YAML与数据库有何不同?..相同的钻取 - 在应用程序代码持久性设置之外.

数据库方法的好处在于它可以以或多或少的安全方式即时更改(不直接打开和覆盖文件).另一个好处是它可以在群集节点之间通过网络共享(如果正确实现).

然而,问题仍然是使用ActiveRecord实现这种设置的正确方法.



3> hoffm..:

您还可以强制执行最多一条记录,如下所示:

class AppConfig < ActiveRecord::Base

  before_create :confirm_singularity

  private

  def confirm_singularity
    raise Exception.new("There can be only one.") if AppConfig.count > 0
  end

end

这会覆盖该ActiveRecord方法,以便在您已经存在的情况下尝试创建该类的新实例时它会爆炸.

然后,您可以继续仅定义作用于一条记录的类方法:

class AppConfig < ActiveRecord::Base

  attr_accessible :some_boolean
  before_create :confirm_singularity

  def self.some_boolean?
    settings.some_boolean
  end

  private

  def confirm_singularity
    raise Exception.new("There can be only one.") if AppConfig.count > 0
  end

  def self.settings
    first
  end

end



4> Derek P...:

我不确定我是否会浪费数据库/ ActiveRecord/Model开销来满足这样的基本需求.这个数据是相对静态的(我假设)并且不需要动态计算(包括数据库查找).

话虽如此,我建议您使用站点范围的设置定义YAML文件,并定义一个初始化文件,将文件加载到常量中.你不会有那么多不必要的活动部件.

没有理由说数据不能仅仅存在于内存中并且为您节省大量复杂性.常量随处可用,无需初始化或实例化.如果你将一个类作为一个单独使用是绝对关键的,我建议你做这两件事:

    undef初始化/新方法

    只定义self.*方法,这样你就无法维持一个状态


使用.yml文件是不灵活的,并且不适合用户(而不是站点作者)能够更新设置.

5> alf..:

我知道这是一个旧线程,但我只需要相同的东西,并发现有一个宝石:acts_as_singleton.

安装说明适用于Rails 2,但它也适用于Rails 3.

推荐阅读
牛尾巴2010
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有