How do I fix Stack Overflow after upgrading rails 2.0.2 to 2.3.5 (or even 2.1.0) => in ActiveRecord::SessionStore - ruby-on-rails

Ok, so we're upgrading a client's legacy code from 2.0.2 to latest rails. Most of the basics were easy to fix, but I can't get to the admin screens. Every time we hit "current_user" we get a "stack level too deep" error.
I've dug deeply into the code (read: flailed around a lot at random) and I've finally narrowed it down to the ActiveRecord::Session store.
The code berks out on the line that includes "session[:user]".
When I spool up script/console I can replicate the stack overflow with the following line:
s = ActiveRecord::SessionStore::Session.new(:session_id => '42', :data => {})
stacktrace to follow.
To make sure it wasn't some weird incompatibility, I blew away the session table in the db and reloaded using rake db:sessions:create and it's still asploding on that line.
SystemStackError: stack level too deep
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/abstract/schema_definitions.rb:68:in `type_cast'
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/dirty.rb:161:in `field_changed?'
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/dirty.rb:132:in `write_attribute_without_dirty'
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/dirty.rb:139:in `write_attribute'
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/attribute_methods.rb:211:in `session_id='
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2746:in `send'
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2746:in `attributes='
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2742:in `each'
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2742:in `attributes='
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2438:in `initialize'
from (irb):10:in `new'
I went into active_record and put in heaps of puts lines. Here's a brief version the final two lines are continually repeated and are clearly the stack-overflow... but why does column_for_attribute(session_id) cause an overflow?
"in respond_to? method: session_id="
"in respond_to? session_id= - there are no generated methods. generating..."
"in respond_to? session_id= - methods generated"
"responds to session_id=? y"
"in respond_to? method: session_id="
"in respond_to? session_id= - super is true"
"in read_attribute: session_id about to fetch value"
"fetched attr value: nil"
"read attr: session_id - value nil"
"column for attribute: session_id"
"c_for_a got col hash - accessing for name: session_id"
"column for attribute: session_id"
"c_for_a got col hash - accessing for name: session_id"
"column for attribute: session_id"
"c_for_a got col hash - accessing for name: session_id"
"column for attribute: session_id"
"c_for_a got col hash - accessing for name: session_id"
Note: we also tried upgrading just to 2.1.0 and the same error occurs (when trying to login - obviously the session-class changed names in between so the scipt/console issue depends on the classname). This time it's endlessly trying just "id" instead of "session_id".
Current environment.rb session settings (for the 2.1.0 version) is below:
# Use the database for sessions instead of the file system
# (create the session table with 'rake db:sessions:create')
config.action_controller.session_store = :active_record_store
config.action_controller.session = { :session_key => "_our_session_id",
:secret=> "some random secret key of your choosing over 30 characters" }
If I drop it back to v2.0.2 it works again.
So I guess the question is: what changed in the ActiveRecord Session between v 2.0.2 and 2.1.0 and how do I make it work?

Ok, looks like the problem was an old back-port/monkey-patch. In the plugins directory we had a back-port of the "dirty" functionality - which I'm guessing must've come out in Rails 2.1.0. All I know is that deleting that plugin seems to have made the "stack level too deep" problem go away (for now). :)

Related

ElasticSearch Rails resource_already_exists_exception when running tests

I'm trying to run one of my tests, which makes a search, trying to assert the inclusion of records in the search result, but in the meantime, I'm receiving a Elasticsearch::Transport::Transport::Errors::BadRequest error:
SearchTest#test_simple_test_returns_product:
Elasticsearch::Transport::Transport::Errors::BadRequest: [400]
{
"error":{
"root_cause":[
{
"type":"resource_already_exists_exception",
"reason":"index [app_application_test_products/FTt1YC6eQrCw2XwJuqjmDw] already exists",
"index_uuid":"FTt1YC6eQrCw2XwJuqjmDw",
"index":"app_application_test_products"
}
],
"type":"resource_already_exists_exception",
"reason":"index [app_application_test_products/FTt1YC6eQrCw2XwJuqjmDw] already exists",
"index_uuid":"FTt1YC6eQrCw2XwJuqjmDw",
"index":"app_application_test_products"
},
"status":400
}
When I perform a search in development, it works as expected, but in tests is throwing such error, within the test I've added an import and an index refresh, nothing else:
class SearchTest < ActiveSupport::TestCase
setup do
Product.import force: true
Product.__elasticsearch__.refresh_index!
end
test "simple test returns product" do
product = products(:one)
I18n.locale = product.market.lang
search = Search.new(
category: product.category.custom_slug,
page: 1,
market_id: product.market_id,
status: "active",
seed: Date.today.to_time.to_i
)
assert_includes search.results.records, products(:one)
assert_includes search.results.records, products(:two)
assert_not_includes search.results.records, products(:three)
end
end
Any help is appreciated, as any hint to improve the code.
I'm using:
# Gemfile
gem 'minitest', '5.10.1'
# Gemfile.lock
elasticsearch (6.1.0)
elasticsearch-model (6.0.0)
elasticsearch-rails (6.0.0)
minitest (= 5.10.1)
I'm glad you found the root cause for your specific issue.
I ran into a similar issue with ruby-on-rails gem for elasticsearch. While the mappings are all fine, i did get the exact same error message. Leaving my answer here so that anyone else who comes here can get more help.
After a lot of trying and error, eventually figured out that the reason is that it's timing out on the create index.
If you change the client timeout to 60 seconds (it failed with 30 seconds), it was able to create the index successfully without causing this intermittent error.
connection_hash = {
hosts: [ "localhost:9220" ]
reload_connections: true
adapter: :httpclient
retry_on_failure: 2
request_timeout: 60
}
es_connection_client = Elasticsearch::Client.new(connection_hash)
Also, found this issue that is related and was closed after a similar answer.
https://github.com/ankane/searchkick/issues/843#issuecomment-384136164
I was using time freezing in multiple specs, so creating a new object with the same created_at time as the object in the previous spec was causing the resource_already_exists_exception error. Slightly adjusting the timestamp to freeze for each spec fixed the problem.
I had the wrong mappings in my model. Instead using the type option, I was using index, what made ElasticSearch to create a multiple mapping. Which isn't available since the version 6.4 (I guess).

"no implicit conversion of nil into String"in the Search Module of Redmine

On the redmine of my company, there is this bug where I get an internal error if I want to search into a project.
Here is the log corresponding to the error:
Processing by SearchController#index as HTML
Parameters: {"utf8"=>"✓", "issues"=>"1", "q"=>"test", "id"=>"sprint"}
Current user: me (id=60)
Completed 500 Internal Server Error in 85.0ms
TypeError (no implicit conversion of nil into String):
lib/plugins/acts_as_searchable/lib/acts_as_searchable.rb:126:in `search'
app/controllers/search_controller.rb:74:in `block in index'
app/controllers/search_controller.rb:73:in `each'
app/controllers/search_controller.rb:73:in `index'
The lines corresponding to the error in the controller are :
if !#tokens.empty?
# no more than 5 tokens to search for
#tokens.slice! 5..-1 if #tokens.size > 5
#results = []
#results_by_type = Hash.new {|h,k| h[k] = 0}
limit = 10
#scope.each do |s|
r, c = s.singularize.camelcase.constantize.search(#tokens, projects_to_search,
:all_words => #all_words,
:titles_only => #titles_only,
:limit => (limit+1),
:offset => offset,
:before => params[:previous].nil?)
#results += r
Here is my config :
Environment:
Redmine version 2.6.9.stable
Ruby version 2.3.0-p0 (2015-12-25) [x86_64-linux]
Rails version 3.2.22
Environment production
Database adapter PostgreSQL
SCM:
Git 1.9.1
Filesystem
Redmine plugins:
no plugin installed
What is interesting is that when I search only one letter, i'm redirected on the search page, but I don't have an internal error.
I'm very new to Redmine developpement and to Ruby, I was just assigned to try to fix this bug. Do any of you have an idea of how to fix it ?
Thanks.
I had the same issue, I was able to fix it by downgrading my ruby & rails version, a working set is :
Rails 3.2.19
Ruby 2.1.4p265
It's look like it's due to a braking change in ruby-2.3.0.
It's really odd. We are using 'Redmine' -2.0.3.1 and we do not have that kind of behaviour.
It seems that "someone" messed up the form linked to the search input. Try to follow that data from when you press enter until it answer you with the 500 error code.
If you can , change the environment to development, this way it will show you more detailed errors.
But I can't help you much more , you didn't provide enough info about the problem.

Activesupport / Multi json: "Did not recognize your adapter specification"

I have a Ruby 1.9.3 / Rails 3.1 project with the following in the gemfile:
gem 'rails', '3.1.12'
gem 'json'
gem 'multi_json', '1.7.7'
That version of rails sets activesupport to 3.1.12 as well. I'm not sure what the exact cause of the problem is, but when running bundle exec rake test, I got the error:
/home/user/.gem/ruby/1.9.3/gems/multi_json-1.7.7/lib/multi_json.rb:121:in 'rescue in load_adapter': Did not recognize your adapter specification. (ArgumentError)
...
(more stack trace, including activesupport methods)
Fortunately I found a solution! See below.
Edit: My original answer is outdated and incorrect; read it if you please, but please read the updated information at the bottom.
After viewing a ton of other questions such as these ones:
OmniAuth Login With Twitter - "Did not recognize your adapter specification." Error
Capistrano deploy: "Did not recognize your adapter specification" during assets:precompile
https://github.com/intridea/multi_json/issues/132
I hadn't found a solution, so I dove into the library and determined that load_adapter was receiving the parameter "JSONGem". The alias was failing, and the method attempted to load
/home/user/.gem/ruby/1.9.3/gems/multi_json-1.7.7/lib/multi_json/adapters/JSONGem.rb
This file doesn't exist, but .../json_gem.rb does exist! So I modified load adapter as follows:
def load_adapter(new_adapter)
# puts "new_adapter: #{new_adapter}" # Debugging
# puts "new_adapater.class: #{new_adapter.class}" # Debugging
case new_adapter
when String, Symbol
new_adapter = ALIASES.fetch(new_adapter.to_s, new_adapter)
new_adapter = "json_gem" if new_adapter =~ /^jsongem$/i # I added this line
# puts "final adapter: #{new_adapter}" # debugging
require "multi_json/adapters/#{new_adapter}"
klass_name = new_adapter.to_s.split('_').map(&:capitalize) * ''
MultiJson::Adapters.const_get(klass_name)
when NilClass, FalseClass
load_adapter default_adapter
when Class, Module
new_adapter
else
raise NameError
end
rescue NameError, ::LoadError
raise ArgumentError, 'Did not recognize your adapter specification.'
end
This fixed the problem for me. It's probably not an optimal solution (ideally I would understand WHY the ALIASES.fetch failed, if that is indeed what happened, and fix that), but if your problem is similar then hopefully this quick fix can help.
Update
It's not viable for deployability reasons to modify someone else's gem. Fortunately I found the root cause of the problem. In project_root/config/initializers/security_patches.rb, we had the line
ActiveSupport::JSON.backend = "JSONGem"
This was the recommended fix to a security bug in older versions of rails. Now that we are on a newer version of rails (i.e, > 3.0), we can simply replace "JSONGem" with "json_gem" (which is what my original modification was doing, in a roundabout way) and not worry about the security issue.

Setting more than one cookie in integration test causes NoMethodError after upgrading rails 2.3

This all worked fine in rails 2.3.5, but when a contractor firm upgraded directly to 2.3.14 suddenly all the integration tests were saying:
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
I have a before_filter on my ApplicationController that sets a bunch of cookies for some javascript to use, and I found that if I comment out all but one of the lines that sets cookie values, it works fine, and it doesn't matter which line I leave in.
before_filter :set_cookies
def set_cookies
cookies['logged_in'] = (logged_in ? 'y' : 'n')
cookies['gets_premium'] = (gets_premium ? 'y' : 'n')
cookies['is_admin'] = (is_admin ? 'y' : 'n')
end
If only one of these lines is active, everything is fine in the integration test, otherwise I get the error above. For example, consider the following test / response:
test "foo" do
get '/'
end
$ ruby -I"lib:test" test/integration/foo_test.rb -n test_foo -v
Loaded suite test/integration/foo_test
Started
test_foo(FooTest): E
Finished in 5.112648 seconds.
1) Error:
test_foo(FooTest):
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
test/integration/foo_test.rb:269:in `test_foo'
1 tests, 0 assertions, 0 failures, 1 errors
But if any two of those cookie setting lines are commented out, I get:
$ ruby -I"lib:test" test/integration/foo_test.rb -n test_foo -v
Loaded suite test/integration/foo_test
Started
test_foo(FooTest): .
Finished in 1.780388 seconds.
1 tests, 0 assertions, 0 failures, 0 errors
The website running in development and production mode works fine - this is just a matter of getting the tests passing. Also, with debugging output I have verified that the error does not get thrown in the method where the cookies get set, that all executes fine, it's somewhere later that the error happens (but the backtrace doesn't tell me where)
This turned out to be a bug in how rack rack writes cookies to the client along with the session cookie. Rack was including double newlines and omitting semi-colons.
Browsers like firefox can handle mildly malformed cookie data, but the integration test client couldn't.
To fix this I had to rewrite the cookie header before sending it to the client.
In environment.rb:
require 'rack_rails_cookie_header_hack'
And in lib/rack_rails_cookie_header_hack.rb:
class RackRailsCookieHeaderHack
def initialize(app)
#app = app
end
def call(env)
status, headers, body = #app.call(env)
if headers['Set-Cookie']
cookies = headers['Set-Cookie']
cookies = cookies.split("\n") if is_str = cookies.is_a?(String)
if cookies.respond_to?(:collect!)
cookies.collect! { |h| h.strip }
cookies.delete_if { |h| h.empty? }
cookies.collect! { |h| h.include?(';') ? h : h + ';' }
end
headers['Set-Cookie'] = is_str ? cookies.join("\n").strip : cookies
end
[status, headers, body]
end
end
Sorry the sources aren't articulated, I actually fixed this awhile ago and came across this questions and figured I'd post my patch.
L0ne's answer works for me, but you also need to include this - it can go at the bottom of lib/rack_rails_cookie_header_hack.rb, providing you're requiring it at the bottom of your environment.rb file - ie after the Rails::Initializer has run:
ActionController::Dispatcher.middleware.insert_before(ActionController::Base.session_store, RackRailsCookieHeaderHack)
Old forgotten issues...
I haven't tested Lone's fix but he has correctly identified the problem. If you catch the exception and print using exception.backtrace, you'll see that the problem is caused by
gems/actionpack/lib/action_controller/integration.rb:329
The offending code is this:
cookies.each do |cookie|
name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2]
#cookies[name] = value
end
If you're like me, and you're only interested in some super quick integration tests, and don't care too much about future maintainability (since it's rails 2), then you can just add a conditional filter in that method
cookies.each do |cookie|
unless cookie.blank?
name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2]
#cookies[name] = value
end
end
and problem solved

Rails - PostGIS + postgis_adapter Geometry Problem

I use postgis_adapter alongside with PostgreSQL 9.0.4, PostGIS 1.5.2 and Rails 3.1.0 on Ruby 1.9.2.
As described in the the postgis_adapter README, I tried to perform
Model.create(:geom => Point.from_x_y(10,20))
Postgres responds with
ERROR: parse error - invalid geometry
HINT: You must specify a valid OGC WKT geometry type such as POINT, LINESTRING or POLYGON
The created GeoRuby Object looks like this:
#<GeoRuby::SimpleFeatures::Point:0x0000010420a620 #srid=4326, #with_z=false, #with_m=false, #y=20, #x=10, #z=0.0, #m=0.0>
Hopefully someone got an idea.
Executive summary: it may work if you change it to:
Model.create(:the_name_of_your_geo_column => Point.from_x_y(10,20))
Longer version, with a high probability of Ruby howlers: I've barely written a word of rb but saw one too many great projects this week to continue in a state of ignorance. Working through the error messages in irb (starting from 0 in the language but very familiar with PostGIS):
ActiveRecord::Base.establish_connection(:adapter=>'postgresql',:database=>'moveable')
pt = TablePoint.new(:data => "Hello!",:geom => Point.from_x_y(1,2))
NameError: uninitialized constant Point
So, require 'postgis_adapter', but then:
PGError: ERROR: relation "table_points" does not exist
This must be that awesome naming convention in ActiveRecord that I've heard about. So create a table called table_points because I don't know what the database model/sync methods are.
moveable=> create table table_points(data text, geo_something geometry);
Notice here I used geometry rather than geography because my first instinct as to your problem was that the modeling methods in the database adapter layer created point types. Not at all, actually. Then again in irb,
pt = TablePoint.new(:geom => Point.from_x_y(1,2))
ActiveRecord::UnknownAttributeError: unknown attribute: geom
No attribute named geom? Just to see what would happen, again in psql:
moveable=> alter table table_points add column geom geometry;
ALTER TABLE
Then:
irb(main):014:0> pt = TablePoint.new(:geom => Point.from_x_y(10,20))
=> #<TablePoint data: nil, geo_something: nil, geom: #<GeoRuby::SimpleFeatures::Point:0x1022555f0 #y=20, #with_m=false, #x=10, #m=0.0, #with_z=false, #z=0.0, #srid=-1>>
irb(main):015:0> pt.save
=> true
Unbelievable! What if I did:
pt = TablePoint.new(:data => 'is this even possible?', :geom => Point.from_x_y(38,121), :geo_something => Point.from_x_y(37,120))
=> #<TablePoint data: "is this even possible?", geo_something: #<GeoRuby::SimpleFeatures::Point:0x102041098 #y=120, #with_m=false, #x=37, #m=0.0, #with_z=false, #z=0.0, #srid=-1>, geom: #<GeoRuby::SimpleFeatures::Point:0x1020410c0 #y=121, #with_m=false, #x=38, #m=0.0, #with_z=false, #z=0.0, #srid=-1>>
irb(main):023:0> pt.save
=> true
Even more unbelievable!
moveable=> select * from table_points;
data | geo_something | geom
--------+-----------------+--------
| | 0101000000000
| 010100000000000 |
| 010100000000000 |
...ble? | 00005E400000000 | 010000405E40
(4 rows)
I hesitate to post this as an answer because of fundamental lack of familiarity with Ruby but the above works (mindbendingly, to me), and you may be able to adapt it to your case.
My knowledge of Rails and Ruby is very limited, but try instead:
class Model < ActiveRecord::Base
end
pt = Model.new(:geom => Point.from_x_y(10,20))
pt.save
Adding a Spatial Reference System Identifier (SRID) fixed this problem for me:
Model.create(:geom => Point.from_x_y(10,20, 4326))
If you're using Google Maps, 4326 is the right SRID. Other maps and vendors might use something else.
I ran into a similar problem using spatial_adapter when upgrading a working app from Rails-3.0 to 3.1. It seems newer versions of ActiveRecord type cast your record to a GeoRuby object during insert. The activerecord-postgis-adapter correctly handles the type cast of your geometry column (presumably to EWKT). I spent a lot of time chasing this today and Aaron Patterson's response in this post was very helpful.
To fix your problem, upgrade your Gemfile and database.yml to use activerecord-postgis-adapter.

Resources