1

我在我的一个模型上为 Rails 应用程序使用单表继承 (STI),并且在将模型对象存储在常量上时遇到问题。我已将问题隔离到一个示例项目中并将其提交到 GitHub:http: //github.com/fcoury/rails-sti-caching

我要做的是在初始化程序(在 Rails/config/initializers/目录中)上加载模型实例(在本例中为 Music 模型,通过 STI 从 Media 模型继承)并将其保持为常量:

MUSIC_CACHE = Hash.new
Music.all.each { |m| MUSIC_CACHE[m.id] = m }

我有一个示例控制器,它执行以下操作:

class MusicsController < ApplicationController
  def index
    require 'pp'
    pp MUSIC_CACHE
    @debug = []
    MUSIC_CACHE.each_pair do |k, v|
      music = Music.find(k)
      d "Object for Music.find(#{k})  => class: #{music.class} - class obj_id: #{music.class.object_id} - #{music.inspect}"
      d "Object for MUSIC_CACHE[#{k}] => class: #{v.class} - class obj_id: #{v.class.object_id} - #{v.inspect}"

      begin
        d "  - Music.is_a?(Media) => #{v.is_a?(Media)}"
        d "  - Try to call name   => #{v.name}"
      rescue
        d "*** Error raised:\n#{$!}"
      end
    end

    @musics = Music.all
  end

  def d(s)
    puts s
    @debug << s
  end
end

以及与之相伴的观点:

<h1 id="music">Music</h1>

<ul>
  <% for m in @musics %>
  <li><%= m.name %> - <%= m.file %></li>
  <% end %>
</ul>

<pre><%=h @debug.join("\n") %></pre>

这段代码第一次运行时,<pre>标签上的输出是这样的:

  Object for Music.find(2)  => class: Music - class obj_id: 13067420 - #<Music id: 2, name: "5th Symphony", file: "5s.mp3", type: "Music", created_at: "2009-05-06 16:31:41", updated_at: "2009-05-06 16:31:41">
  Object for MUSIC_CACHE[2] => class: Music - class obj_id: 13067420 - #<Music id: 2, name: "5th Symphony", file: "5s.mp3", type: "Music", created_at: "2009-05-06 16:31:41", updated_at: "2009-05-06 16:31:41">
    - Music.is_a?(Media) => true
    - Try to call name   => 5th Symphony

但是,如果我只是重新加载页面,则会输出以下内容:

Object for Music.find(2)  => class: Music - class obj_id: 18452280 - #<Music id: 2, name: "5th Symphony", file: "5s.mp3", type: "Music", created_at: "2009-05-06 16:31:41", updated_at: "2009-05-06 16:31:41">
Object for MUSIC_CACHE[2] => class: Music - class obj_id: 13067420 - #<Music id: 2, name: "5th Symphony", file: "5s.mp3", type: "Music", created_at: "2009-05-06 16:31:41", updated_at: "2009-05-06 16:31:41">
  - Music.is_a?(Media) => false
*** Error raised:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.include?

有谁知道这个错误背后的原因?

4

2 回答 2

2

我的第一个想法是 Rails 在服务请求后释放(无效)所有模型对象。因此class: Music - class obj_id: 13067420在第二个请求中变得不可用。我建议查看 ActiveRecord 源代码并找出谁使模型对象无效。

这个rails模型缓存教程也很有用:http ://railscasts.com/episodes/115-caching-in-rails-2-1

于 2009-05-06T17:52:43.113 回答
0

基本上,你不能那样做。

在开发环境中,每个请求都会重新加载您的类。这意味着它们被完全摧毁和重建。原来的类对象消失了,一个新的对象取而代之。

如果您在请求之间保留一个对象,则在第二个请求中,该对象仍将继承自原始类,即已删除的类。指向该类的常量现在指向一个新的类对象,它可能与前一个相同也可能不同,具体取决于您是否更改了类定义或影响它的插件,但它仍然是一个不同的类对象内存,旧对象将不知道它应该从这个新的类对象继承。

我假设如果您在生产环境中运行您的应用程序,它会工作。

于 2009-05-07T01:30:16.523 回答