新手问题 自定义 method_missing 后显示 stack too deep

alixiaomiao · 2014年06月19日 · 最后由 alixiaomiao 回复于 2014年06月19日 · 2038 次阅读

Setting model 有 name 和 value 两个字段,用来存储站点的相关设置,比如

name value
site_title xxxx
site_description xxxxx
site_url xxxxx

如果要获取某个设置项的值,需要这么写

Setting.find_by_name('site_title').value

我想直接用 Setting.site_title 来获取设置项,于是我重写了 method_missing

class Setting < ActiveRecord::Base
  validates_presence_of   :name, :value
  validates_uniqueness_of :name

  class << self
    alias :old_method_missing :method_missing

    def method_missing(method, *arg)
      setting = find_by_name(method)

      # 如果能找到,就返回 value
      if setting.nil?
        setting.value
      else
        # 否则调用原来的 method_missing
        old_method_missing(method, *arg)
      end
    end
  end
end

但是这样之后,就会显示 stack level too deep

pry(main)> Setting.site_title
SystemStackError: stack level too deep
from /usr/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/pry_instance.rb:353

请问这个是怎么回事?

找到问题了,有两处错误

  1. setting = find_by_name(method) 改成 setting = find_by(name: method)

前者本就是个幽灵方法,所以要用非幽灵方法的 find_by

  1. if setting.nil? 改成 unless setting.nil?

这个是我脑子短路了,逻辑搞错了。

meta programming 在这里有些滥用了

要是就那么几个简单设定,没有任何 association 的话不如直接写在程序 yml 里作为设定,没有必要进入数据库。

要是你的应用类似于建站工具,每个用户都有设定的话,可以把所有 setting 作为一个字段 serialize,然后直接从 hash 里面取任何值。

#2 楼 @billy 感谢您的建议,我是初学者,跟着 guides,就着 api,练习做一个 blog 系统。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号