Ich habe mit einigen der internen Schienen-Code in Rails 4.2.7 mit Feder preloader experimentiert und einige ungerade Verhalten von Stack-Dumps in irb gefunden.Blöcke und Call-Bereich in IRB Verhalten inkonsistent
Betrachten Sie den folgenden Code
def run_block
yield
end
class Vehicle < ActiveRecord::Base
def self.instantiate(*args)
puts caller_locations
super
end
def self.test_stack
run_block {Vehicle.all}
end
end
Mitteilung, dass ich die Funktionalität der instantiate Funktion erstreckt (http://apidock.com/rails/ActiveRecord/Base/instantiate/class) aus dem Call-Stack zu drucken.
Wenn ich eine Schiene c Konsole öffnen und laufe
run_block {puts caller_locations}
Ich erhalte den Stack-Trace
test_irb/app/models/vehicle.rb:2:in `run_block'
(irb):4:in `irb_binding'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb/workspace.rb:87:in `eval'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb/workspace.rb:87:in `evaluate'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb/context.rb:380:in `evaluate'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb.rb:489:in `block (2 levels) in eval_input'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb.rb:623:in `signal_status'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb.rb:486:in `block in eval_input'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb/ruby-lex.rb:246:in `block (2 levels) in each_top_level_statement'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb/ruby-lex.rb:232:in `loop'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb/ruby-lex.rb:232:in `block in each_top_level_statement'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb/ruby-lex.rb:231:in `catch'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb/ruby-lex.rb:231:in `each_top_level_statement'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb.rb:485:in `eval_input'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb.rb:395:in `block in start'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb.rb:394:in `catch'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb.rb:394:in `start'
...
Aber laufen (vorausgesetzt, ich habe einige Zeilen in der db)
run_block {Vehicle.all}
Ich bekomme den Stack-Trace
.rvm/gems/ruby-head/gems/activerecord-4.2.7/lib/active_record/querying.rb:50:in `block (2 levels) in find_by_sql'
.rvm/gems/ruby-head/gems/activerecord-4.2.7/lib/active_record/result.rb:51:in `block in each'
.rvm/gems/ruby-head/gems/activerecord-4.2.7/lib/active_record/result.rb:51:in `each'
.rvm/gems/ruby-head/gems/activerecord-4.2.7/lib/active_record/result.rb:51:in `each'
.rvm/gems/ruby-head/gems/activerecord-4.2.7/lib/active_record/querying.rb:50:in `map'
.rvm/gems/ruby-head/gems/activerecord-4.2.7/lib/active_record/querying.rb:50:in `block in find_by_sql'
.rvm/gems/ruby-head/gems/activesupport-4.2.7/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
.rvm/gems/ruby-head/gems/activerecord-4.2.7/lib/active_record/querying.rb:49:in `find_by_sql'
.rvm/gems/ruby-head/gems/activerecord-4.2.7/lib/active_record/relation.rb:639:in `exec_queries'
.rvm/gems/ruby-head/gems/activerecord-4.2.7/lib/active_record/relation.rb:515:in `load'
.rvm/gems/ruby-head/gems/activerecord-4.2.7/lib/active_record/relation.rb:243:in `to_a'
.rvm/gems/ruby-head/gems/activerecord-4.2.7/lib/active_record/relation.rb:630:in `inspect'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb/inspector.rb:109:in `block in <module:IRB>'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb/inspector.rb:102:in `inspect_value'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb/context.rb:384:in `inspect_last_value'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb.rb:661:in `output_value'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb.rb:490:in `block (2 levels) in eval_input'
.rvm/rubies/ruby-head/lib/ruby/2.4.0/irb.rb:623:in `signal_status'
, die nicht zeigt, dass der Block in der Methode run_block
irgendwo in der Ablaufverfolgung geschachtelt wurde. Running run_block {puts Vehicle.all}
zeigt jedoch die run_block-Funktion in der Stack-Ablaufverfolgung. Außerdem zeigt Vehicle.first
im Block den erwarteten Stack-Trace. Noch Vehicle.test_stack
oben definiert zeigt weder die run_block
Methode noch die test_stack
Methode im Stack-Trace. Kann jemand diese Inkonsistenz erklären? Ist das ein Ergebnis von Ruby-Sprachkonstrukten oder etwas mit der Implementierung der .all
Methode? Danke allen!
Wow, komplizierter als erwartet. Danke für die Antwort! – SJH
@SJH der Grund, warum ActiveRecord zu diesem Problem geht, ist es, Aufrufe von Beziehungen zu verketten, wie in den Antworten auf diese Frage ganz schön erklärt: http://stackoverflow.com/questions/10747106/how-does-rails-activerecord-chain -where-Klauseln-ohne-mehrere-Abfragen – philomory