我们最近更新了一个应用程序到Rails 3.0.4(在线开发服务器上的3.0.5).从2.3.10到3.0.4的大多数变化都是由于过时或过时的插件和宝石,并且相对容易解决.但有一件事让我发疯:
在开发模式下,每个Web请求都会导致服务器进程分配比以前多 50-60 MB的内存.请求后不释放此内存,至少不是全部内存.在10-20个请求之后,每个Ruby实例消耗超过500 MB的RAM,而我们以前的Rails 2.3.10实例很少超过200 MB.
这使得无法运行我们的1300次测试,因为在测试结束之前,开发了4GB的RAM.它只发生在开发模式中cache_classes = false.如果我将cache_classes切换为true,Rails实例将消耗大约200MB的内存,然后保留在那里.但是,在测试期间,即使cache_classes = true,内存使用量也会增加.
我查询了ObjectSpace并发现每次请求时,大约有3500个新的Proc,最多50'000个新的Strings和3000个新的Hashes和Arrays被创建并且没有被释放.这些字符串(转储时)包含我的整个源代码,包括插件和gem,文档,源代码注释和路径名.(为什么?)
为了找到原因,这是我尝试过的:(每次更改后,我都会使用ab -n 50.)
pg, rails, aasm, will_paginate, geokit-rails3, koala, omniauth, paperclip …我使用Rails 3.0.4和RSpec 2.5.例如,在我的控制器中,我大量使用命名范围
@collection = GuestbookEntry.nonreplies.bydate.inclusive.paginate(
:page => params[:page], :conditions => { ... })
在我的测试中,我希望能够模拟这种查询的结果,而不是措辞.我觉得做某事并不合理
GuestbookEntry.stub_chain(:nonreplies, :bydate, ...).and_return(...)
因为当我决定重新排序命名范围时,此测试将失败.
使用Rails 2.3和RSpec 1.x,这很好用:我可以写
GuestbookEntry.should_receive(:find).with(:all, :conditions => { ... })
并且上述调用将被捕获并正确处理.然而,使用Rails 3,由于某种原因,这不再起作用.
为什么?如何设置嵌套范围结果的期望值或存根?由于Rails 3的ActiveModel中的所有内容都是命名范围(感谢ARel),因此必须以某种方式实现,否则测试确实非常脆弱.
谢谢!
更新:另请参阅GitHub上的问题报告.
Bundler文档说,为了在通过Capistrano部署时安装所有必需的bundle,只需插入即可
require 'bundler/capistrano' # siehe http://gembundler.com/deploying.html
Run Code Online (Sandbox Code Playgroud)
在他的deploy.rb中.然后,在部署时,Capistrano打电话
* executing "bundle install --gemfile .../releases/20110403085518/Gemfile \
--path .../shared/bundle --deployment --quiet --without development test"
Run Code Online (Sandbox Code Playgroud)
这很好用.
但是,我们的生产服务器上有一个分段设置,与真实的实时站点隔离,我们在那里测试带有(克隆和防火墙)实时生产数据的新应用程序版本.在那里,我们需要安装测试和开发宝石.
如何在此处指定capistrano命令行?是否有我可以使用的参数,或者我是否需要设置自己的capistrano任务来覆盖Bundler?
谢谢!
我有以下型号.用户有UserActions,一个可能的UserAction可以是ContactAction(UserAction是一个多态).还有LoginAction等其他动作.所以
class User < AR::Base has_many :contact_requests, :class_name => "ContactAction" has_many :user_actions has_many_polymorphs :user_actionables, :from => [:contact_actions, ...], :through => :user_actions end class UserAction < AR::Base belongs_to :user belongs_to :user_actionable, :polymorphic => true end class ContactAction < AR::Base belongs_to :user named_scope :pending, ... named_scope :active, ... end
这个想法是一个ContactAction加入两个用户(在应用程序中有其他后果),并始终有一个接收端和一个发送端.同时,ContactAction可以具有不同的状态,例如过期,待定等.
我可以说@user.contact_actions.pending或@user.contact_requests.expired列出用户发送或接收的所有待处理/过期请求.这很好用.
我现在想要的是一种加入两种类型的ContactAction的方法.即@user.contact_actions_or_requests.我尝试了以下方法:
class User def contact_actions_or_requests self.contact_actions + self.contact_requests end # or has_many :contact_actions_or_requests, :finder_sql => ..., :counter_sql => ... end
但是所有这些都存在这样的问题:在关联之上不可能使用额外的finder或named_scopes,例如@user.contact_actions_or_requests.find(...)或 …
我正在将Rails应用程序移植到Rails 4.2.这个Rails应用程序在关联中包含一些相当复杂的手动SQL代码 - 部分是由于DB优化(例如子选择而不是JOIN),部分原因是由于在编写时没有可行的替代方案(Rails 3.0),部分原因是由于缺乏知识(我希望,至少 - 这很容易解决).
示例:InternalMessage类.可以在用户之间发送消息(InternalMessage的收件人和消息的"删除",存储在InternalMessagesRecipients中,因为可以有几个)并且可以读取,回复,转发和删除它们.该关联看起来像这样:
class User < AR::Base
has_many :internal_messages,
:finder_sql => "SELECT DISTINCT(internal_messages.id), internal_messages.* FROM internal_messages " +
' LEFT JOIN internal_messages_recipients ON internal_messages.id=internal_messages_recipients.internal_message_id' +
' WHERE internal_messages.sender_id = #{id} OR internal_messages_recipients.recipient_id = #{id}',
:counter_sql => 'SELECT count(DISTINCT(internal_messages.id)) FROM internal_messages ' +
' LEFT JOIN internal_messages_recipients ON internal_messages.id=internal_messages_recipients.internal_message_id' +
' WHERE internal_messages.sender_id = #{id} OR internal_messages_recipients.recipient_id = #{id}'
# ...
end
Run Code Online (Sandbox Code Playgroud)
关键部分是最后的"OR"子句 - 通过这种关联,我希望获得接收和发送的消息,这些消息与用户表单独连接:
has_many :sent_messages, -> { where(:sender_deleted_at => nil) }, :class_name => 'InternalMessage', …Run Code Online (Sandbox Code Playgroud) 这有点类似于PostgreSQL中的获取日期列表,但不完全相同(我认为).
我有一个SQL表,其中每一行都包含一个开始和结束日期.我想形成一个查询,以便对于每一行,对于此范围内的每个日期,我得到一个结果.
例如: id=1, title=MyRange, start=2012-08-05, end=2012-08-08
查询: SELECT * FROM myTyble where id=1 AND ...
结果:
id=1, title=MyRange, date=2012-08-05
id=1, title=MyRange, date=2012-08-06
id=1, title=MyRange, date=2012-08-07
id=1, title=MyRange, date=2012-08-08
Run Code Online (Sandbox Code Playgroud)
我意识到在这个结果集中将复制唯一和主键行,但这对我来说无关紧要.任何想法都会非常受欢迎!
我正在编写一个应用程序,其中许多(但不是全部)ActiveRecord模型都有一hash列.这是使用随机MD5哈希创建时填充的,用于引用单个对象而不是其ID.为实现这一目标,我在相应的型号中包含了以下模块,并find_by_id_or_hash!()在所有控制器中使用而不是find:
module IdOrHashFindable
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
before_create :create_hash ## <-- THIS FAILS
# legacy. in use only until find by ID is phased out altogether
def find_by_id_or_hash!(id_or_hash)
id_or_hash.to_s.size >= 32 ? find_by_hash!(id_or_hash) : find(id_or_hash)
end
end
def to_param; self.hash end
def create_hash; self.hash = Support.create_hash end
end
Run Code Online (Sandbox Code Playgroud)
为了保持干燥,我想before_create在模块内部进行调用.但是,我一直在努力
undefined method `before_create' for IdOrHashFindable:Module
Run Code Online (Sandbox Code Playgroud)
要么
undefined method `before_create' for IdOrHashFindable::ClassMethods:Module
Run Code Online (Sandbox Code Playgroud)
取决于我把它放在哪里.这是有道理的(毕竟,我正在调用一个函数,而不是定义它),但我仍然想知道如何做到这一点.(before_create因为还有其他before_create调用,我无法覆盖).
此外,对于包含此模块的所有型号,都应用非常类似的测试.我如何持续测试此功能?我是否将自定义describe ... end块 …
activerecord ×2
postgresql ×2
activemodel ×1
arel ×1
associations ×1
bdd ×1
bundler ×1
capistrano ×1
date ×1
finder-sql ×1
memory-leaks ×1
module ×1
polymorphism ×1
production ×1
range ×1
rspec-rails ×1
rspec2 ×1
ruby ×1
sql ×1
staging ×1