开发者

"each"/"map" on array results in "You have a nil object when you didn't expect it" in create_time_zone_conversion_attribute?, sporadically

开发者 https://www.devze.com 2023-01-24 16:40 出处:网络
I have a button which is sending a get request over XHR to a specific action in a rails server. This action calls a function I defined in the model \"Category\". This function does something like x=Ca

I have a button which is sending a get request over XHR to a specific action in a rails server. This action calls a function I defined in the model "Category". This function does something like x=Category.subcategories, and in the next line something like x.map(&:id), or x.each {|x| y << x.id}. (Category has_many :subcategories). In my development environment this works for 1-10 clicks on this button, but then stops working for the following reason:

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?

With the following dump:

C:/MyApp/vendor/rails/activerecord/lib/active_record/attribute_methods.rb:142:in `create_time_zone_conversion_attribute?'
C:/MyApp/vendor/rails/activerecord/lib/active_record/attribute_methods.rb:75:in `define_attribute_methods'
C:/MyApp/vendor/rails/activerecord/lib/active_record/attribute_methods.rb:71:in `each'
C:/MyApp/vendor/rails/activerecord/lib/active_record/attribute_methods.rb:71:in `define_attribute_methods'
C:/MyApp/vendor/rails/activerecord/lib/active_record/attribute_methods.rb:355:in `respond_to?'
C:/MyApp/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb:215:in `method_missing'
C:/MyApp/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb:215:in `map'
C:/MyApp/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb:215:in `send'
C:/MyApp/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb:215:in `method_missing'
C:/MyApp/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb:369:in `method_missing'
C:/MyApp/app/models/category.rb:24:in `fetch_prices_grouped_by_date'
C:/MyApp/app/controllers/categories_controller.rb:103:in `show'

Restarting the server fixes the problem for the next 1-10 clicks and then it reappears. When debugging that line (on NetBeans IDE, ruby-debug-ide-0.3.1), I get (after crossing the 1-10 "good clicks") to the method_missing (method="map", self="{Array, 23 elements}"), and if I try to expand the watch on variable x, the debug server crashes. Following the advice of this post, I edited my environment.rb and turned class caching on:

config.cache_classes = true

and the problem is solved. However, it is very annoying to restart the server after each change in code, and I was wondering if anyone has an idea of what is going on, why changing the cache_classes solves it, and if there is any other workaround that doesn't carry the pain of restarting after every edit.

I'm using Rails 2.3.8.

Many thanks, Amit

EDIT:

OK, so after some more debugging I realize it fails on having skip_time_zone_conversion_for_attributes set to nil for some reason in create_time_zone_conversion_attribute? method (active_record/attribute_methods.rb).

Found this article after some research. Adding:

self.skip_time_zone_conversion_for_attributes = []

to the model doesn't work.

Replacing in environment.rb

config.time_zone = 'UTC'

with

config.active_record.default_timezone = :utc

doesn't work for me either, as I get "stack level too deep" with:

C:/MyApp/vendor/rails/activerecord/lib/active_record/attribute_methods.rb:237:in `method_missing'
C:/MyApp/vendor/rails/activerec开发者_JAVA百科ord/lib/active_record/attribute_methods.rb:253:in `method_missing'
C:/MyApp/vendor/rails/activerecord/lib/active_record/attribute_methods.rb:211:in `to_proc'
C:/MyApp/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb:369:in `method_missing'
C:/MyApp/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb:215:in `map'
C:/MyApp/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb:215:in `send'
C:/MyApp/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb:215:in `method_missing'
C:/MyApp/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb:369:in `method_missing'
C:/MyApp/app/models/category.rb:24:in `fetch_prices_grouped_by_date'
C:/MyApp/app/controllers/categories_controller.rb:103:in `show'

I'll investigate it further to see if it's just a specific issue with my code.

EDIT #2

Ok, per this article's recommendation I edited attributes_methods.rb line 252 and changed it from:

if self.class.primary_key.to_s == method_name

to:

if false and self.class.primary_key.to_s == method_name

And now it works. However, not sure I like messing around with the framework's code. Would appreciate any other suggestions for workarounds.

Thanks! Amit

Edit #3

Ok, this last change broke other parts of my application. I have reposted this question here.


Finally solved! After posting a third question and with help of trptcolin, I could confirm a working solution.

The problem: I was using require to include models from within Table-less models (classes that are in app/models but do not extend ActiveRecord::Base). For example, I had a class FilterCategory that performed require 'category'. This messed up with Rails' class caching. I had to use require in the first place since lines such as Category.find :all failed.

The solution (credit goes to trptcolin): replace Category.find :all with ::Category.find :all. This works without the need to explicitly require any model, and therefore doesn't cause any class caching problems.

The "stack too deep" problem also goes away when using config.active_record.default_timezone = :utc

0

精彩评论

暂无评论...
验证码 换一张
取 消