我有一组ActiveRecord模型,我预先加载它们以避免N + 1问题。为了帮助完成这个过程,我希望能够进行一些手动测试,其中(概念上)块看起来如下所示:
# Prepare some data
data = Foo.includes(:bar, {baz: :quux}).find(27)
ActiveRecord.raise_error_if_any_queries_occur
perform_some_work_with_data(data)
ActiveRecord.back_to_normal
这似乎应该是一种方法,但我没有运气。还有其他人这样做过吗?
答案 0 :(得分:5)
您可以断开ActiveRecord与数据库的连接,并在完成后重新连接:
data = Foo.includes(:bar, {baz: :quux}).find(27)
Foo.connection.disconnect!
perform_some_work_with_data(data)
Foo.connection.reconnect!
如果在ActiveRecord断开连接时尝试对数据库运行查询,则会引发错误。
答案 1 :(得分:0)
您可以通过以下方式断开与数据库的连接:
ActiveRecord::Base.connection.disconnect!
Rails.logger.info('Disconnected from database')
perform_some_work_with_data(data)
ActiveRecord::Base.establish_connection
Rails.logger.info('Connected to database')
但我认为这有点奇怪。我更喜欢使用bullet gem进行N + 1查询检测。
答案 2 :(得分:0)
rails中的查询将在某处调用此处定义的select_all(arel, name = nil, binds = [])
方法:
https://github.com/rails/rails/blob/89a7187cc0d893da67f53d3215a33043905d68ed/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb#L22
您可以看到此方法将处理select(sql, name = nil, binds = [])
方法的查询。此外,由于使用了undef_method,因此该方法处理对其父方法的查询:选择您可以在其定义中选择的内容:
https://github.com/rails/rails/blob/89a7187cc0d893da67f53d3215a33043905d68ed/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb#L354
最后,这意味着执行的select方法是ConnectionAdapter方法,例如posgresql适配器,如第946行所示: https://github.com/rails/rails/blob/89a7187cc0d893da67f53d3215a33043905d68ed/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
所以,第一个选项: - 例如,您可以编辑其中一个文件以包含它们被调用的一些信息。
其次,我不知道它是否会起作用:
- 您可以重写select_all(arel, name = nil, binds = [])
以引发异常,例如:
def select_all(arel, name = nil, binds = [])
raise "error"
end
如果您想取消此覆盖,您可以使用以下方法取消您的方法:
undef_method :select_all
所以你要把select_all传递给父。
但同样,我不知道第二个是否有效,但第一个确实有效,尽管编辑rails core以包含日志功能非常具有侵略性。
答案 3 :(得分:-2)
如果您删除find(27)
并使用where(id: 27)
,则可以将.to_sql
追加到最后。
data = Foo.includes(:bar, {baz: :quux}).where(id: 27).to_sql
然后用:
执行它Foo.find_by_sql(data)
你也可以用Arel完成同样的事情。 Arel将允许您构建更复杂的查询,您可以在需要时执行这些查询。