开发者

read_inheritable_attribute unexpectedly modified in production

This is happening in Rails 3.0.7 and 3.0.9, WEBrick and Apache.

I have a module Reportable that has a method that writes an 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 is loaded in config/initializers and a class uses it:

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

In production mode, the first time I load a page after the server starts, the attribute loads correctly:

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

But on the second page load:

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

It works as expected in development, and in the console in production mode. The problem only appears in a POST request on the web server in production mod开发者_如何学运维e. What gives?


Just tried, it works in all environments without problem. Any other details?


Otherwise:

  • why do you use instance_eval since you're working on the model itself?

  • you should use a splat to pass arguments

This would lead to:

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

And in model:

include Reportable
add_reports :report1, :report2


After a lot of headaches, the cause was that read_inheritable_attribute returned a reference rather than value.

The action throwing the error redirected to another action, which was the true cause of the problem. The module had another method:

def available_reports
  read_inheritable_attribute(:reportable_report_names)
end

And the other action did this:

# @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

Because available_reports returned a reference, the dup did nothing and the keep_if deleted my precious values from the class variable.

The fix was:

properties = properties.dup.keep_if...

Thanks to those who took the time to check this question out even though there wasn't enough information in it to be answered properly.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜