我试图延长ActiveRecord模型( Vote
),一个宝石( https://github.com/peteonrails/vote_fu )提供了我的申请。 (即,没有vote.rb
在app/models
)
我的第一个方法是创建一个名为文件lib/extend_vote.rb
包含的代码:
Vote.class_eval do
after_create :create_activity_stream_event
has_one :activity_stream_event
def create_activity_stream_event
# something..
end
end
在创建第一个投票的时候这个工作,但是当我尝试创建以后每次投票我得到的错误TypeError (can't dup NilClass)
我觉得这个错误是由一个事实,即造成Vote
类的每个请求后自动加载,但在代码lib/extend_vote.rb
只加载一次服务器启动时,这将导致has_one :activity_stream_event
协会的行为古怪。 (另外,问题消失,如果我设置config.cache_classes = true
在development.rb
)
为了解决这个问题,我试图通过添加使投票扩展在每次请求重新加载to_prepare
块到我的development.rb
:
config.to_prepare do
load 'extend_vote.rb'
end
这解决了(can't dup NilClass)
问题,但现在每当我创建一个新的投票中, create_activity_stream_event
回调函数被调用的额外时间。 即,第一投称之为一次,第二次调用它两次,等,等,所以它似乎像to_prepare
块太积极重装的延伸和添加重复回调。
什么是方法和添加回调的最佳方式Vote
模式呢?
Answer 1:
[UPDATE:应防止模块被正确的解决方案包括在同一类几次]
我相信你可以使用的ActiveSupport ::关注 ,以防止模块被包括多次而导致的回调叫来几个时间。 看下面的例子:
module VotePatch
extend ActiveSupport::Concern
included do
after_create :create_activity_stream_event
has_one :activity_stream_event
end
module InstanceMethods
def create_activity_stream_event
#your code here
end
end
end
Vote.send(:include, VotePatch)
Answer 2:
提醒一句:这是一个非常古老的宝石(最后一次提交的是3岁)和它的外观作为是不会与钢轨3.X工作。 在Rails 3.x的引擎使得这类东西比较容易的方式。
据我所知,在第一种情况下的问题不在于投票模型被重新加载(它不应该),但该activity_stream_event
模型重新加载。 由于投票模型没有重载协会是左挂到的版本activity_stream_event
类从重装前。 由于轨道的胆量了班,他们得到重新加载之前,这会导致问题。
有了这个矿,试试这个黑客:
#in config/initializers/abstract_vote.rb
AbstractVote = Vote
AbstractVote.abstract_class = true
Object.send :remove_const, :Vote
#in app/models/vote.rb
class Vote < AbstractVote
after_create :create_activity_stream_event
has_one :activity_stream_event
def create_activity_stream_event
end
end
这样做是什么让你有从一个创业板继承了自己的投票类。
但同样,我希望你找到更高达日期或推出自己的(宝石只〜250红宝石线)
Answer 3:
我想尝试什么agmcleod提出的意见,但不是把它在lib中,把它在配置/初始化/ vote.rb:
class Vote
after_create :create_activity_stream_event
has_one :activity_stream_event
def create_activity_stream_event
# something..
end
end
当然,你可以用叉子叉的宝石,让您的修改,并链接到你的Gemfile的分叉版本(这是我的偏好)。
Answer 4:
阿德里安Coquio有正确的想法ActiveSupport::Concerns
,这是Rails的方式来扩展模型。 他的代码将工作,你应该使用它。
然而,这将无法工作在发展所有的时间,因为当Rails的重新加载你的类时,一个文件的更改,也不会重新evaulate的#send
线。 我能找到的是连接到一个唯一的解决办法ActionDispatch
生产回调以确保文件是每个页面加载后重新要求:
if Rails.env.development?
ActionDispatch::Callbacks.to_prepare do
require_dependency "../../lib/vote_fu_extensions"
end
end
在生产中,或者如果你设置cache_classes
在你的配置为true,你不会需要做到这一点。
- 来源
- RoR的引导有关配置
- 这表明它已被弃用 ,你应该使用
ActionDispatch::Reloader
回调呢? 还没试过。
Answer 5:
你的问题可能是由于这样的事实,你是猴子修补类。 当铁轨试图重新加载常数是不考虑你的文件。
尝试使用模块技术为如下。
添加一个名为lib/vote_fu_extension.rb
module VoteFuExtension
def self.included(base)
base.has_one :activity_stream_event
base.after_create :create_activity_stream_event
end
def create_activity_stream_event
# something..
end
end
Vote.send(:include, VoteFuExtension)
添加称为初始化config/initializers/vote_fu.rb
require "vote_fu_extension"
注意
如果你想类方法添加到Vote
模型参考这个答案 。
无耻插头:我叉的的vote_fu
宝石有一些新的功能和增强功能。
Answer 6:
你可以尝试这样的事:
class Vote
after_create :create_activity_stream_event
has_one :activity_stream_event
def create_activity_stream_event
# something..
end
end
我觉得比它会增加你的功能和通话功能“after_create”和“has_hone”。
文章来源: Re-open an ActiveRecord model that's provided by a gem