【问题标题】:read_inheritable_attribute unexpectedly modified in productionread_inheritable_attribute 在生产中意外修改
【发布时间】:2011-08-10 14:07:46
【问题描述】:

这发生在 Rails 3.0.7 和 3.0.9、WEBrick 和 Apache 中。

我有一个模块Reportable,它有一个写inheritable_attribute的方法:

module Reportable
  module ClassMethods
    def add_report(report_name)
      instance_eval do
        write_inheritable_hash(:reportable_report_names,
          {report_name => {:dates => true, :details => 'something'})
        end
      end
    end
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

Reportable 被加载到 config/initializers 并且一个类使用它:

class User < ActiveRecord::Base
  include Reportable
  add_report :report1
  add_report :report2
end

在生产模式下,服务器启动后第一次加载页面,属性加载正确:

User.read_inheritable_attribute(:reportable_report_names)
# => {:report1 => {:dates => true, :details => 'something'},
      :report2 => {:dates => true, :details => 'something'}}

但是在第二页加载时:

User.read_inheritable_attribute(:reportable_report_names)
# => {:report1 => {:dates => true},
      :report2 => {:dates => true}}

它在开发中按预期工作,在生产模式下在控制台中工作。该问题仅出现在生产模式下 Web 服务器上的 POST 请求中。什么给了?

【问题讨论】:

标签: ruby-on-rails metaprogramming


【解决方案1】:

刚试过,它在所有环境中都可以正常工作。还有其他细节吗?


否则:

  • 既然您正在处理模型本身,为什么还要使用instance_eval

  • 你应该使用 splat 来传递参数

这会导致:

module ClassMethods
  def add_reports(*report_names)
    report_names.each do |report_name|
      write_inheritable_hash(:loggable_report_names,
        {report_name => {:dates => true, :details => 'something'})
      end
    end
  end
end

在模型中:

include Reportable
add_reports :report1, :report2

【讨论】:

  • 简化了...Reportable 包含在许多类中,每个类都有一组不同的报告。每个报告都会生成一个名称(用于制作报告方法)和选项哈希(存储在:loggable_report_names 中,报告方法名称作为键)。模块中还有其他几种方法可以更轻松地检索报告名称及其选项。
  • 不是答案......但无论如何都要支持帮助。谢谢!我期待 read_inheritable_attribute 返回一个值而不是一个引用。
  • 也许您可以在“包含”块中创建对象?
  • 是的,它也试过了(还有很多其他的东西......通过排列编程?),但它没有用。该问题没有足够的信息来回答,我已将最终解决方案放在答案中。
【解决方案2】:

经过一番头疼,原因是read_inheritable_attribute返回的是引用而不是值。

引发错误的操作重定向到另一个操作,这是问题的真正原因。该模块有另一种方法:

def available_reports
  read_inheritable_attribute(:reportable_report_names)
end

另一个动作是这样做的:

# @model_reports = a hash of 'model_class_name'.to_sym => model.available_reports.dup
@model_reports.each do |model, model_reports|
  model_reports.each do |name, properties|
    properties = properties.keep_if... # remove per the view's requirements
  end
end

因为available_reports 返回了一个引用,dup 什么也没做,keep_if 从类变量中删除了我宝贵的值。

解决方法是:

properties = properties.dup.keep_if...

感谢那些花时间检查这个问题的人,即使它没有足够的信息来正确回答。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多