unable to get content-length header working under rails 4.1+puma - ruby-on-rails

Setup is: Puma: 2.9.1
Rails: 4.1.5
Rack: 1.5.2
As per documentation i tried to get ContentLength header working by adding fallowing to my application.rb
config.middleware.use Rack::ContentLength
Unfortunately response was still chunked. After some investingation i found following condition in Rack::ContentLength class:
if !STATUS_WITH_NO_ENTITY_BODY.include?(status.to_i) &&
!headers['Content-Length'] &&
!headers['Transfer-Encoding'] &&
body.respond_to?(:to_ary)
body.respond_to?(:to_ary) is only one which yields false. At that context body is instance of Rack::BodyProxy in which responds_to? is overriden:
def respond_to?(*args)
return false if args.first.to_s =~ /^to_ary$/
super or #body.respond_to?(*args)
end
I am really confused here. Removing body.respond_to?(:to_ary) resolves issue, but i dont feel safe just removing chunks of code from rack lib. Any help getting content-length header working are appreciated. Thanks.

Related

Unable to check response size with Rack Deflater

I'm trying to use Rack::Deflater to compress responses when the body is greater than 512 bytes in size.
Using the example given in the latest Rack Deflater source code in my config.ru I get the following error:
/gems/rack-1.5.5/lib/rack/deflater.rb:20:in `initialize': wrong number
of arguments (2 for 1) (ArgumentError)
Any idea what I'm doing wrong here? Any documentation I've found online suggests the syntax I'm using is correct. I'm using RoR 4 and Rack 1.5.5.
This is my config.ru file in its entirety:
require ::File.expand_path('../config/environment', __FILE__)
require 'rack'
use Rack::Deflater, :if => lambda { |*, body| sum=0; body.each { |i| sum += i.length }; sum > 512 }
run Rails.application
I suspect it's some kind of versioning error but I'm unsure.
Yes, you are right. It's version issue. You paste code from the very last version (2.0.3/2.0.4), but according to your trace you have 1.5.5 in your local setup.
Here you can see that Rack::Deflater doesn't accept any additional options in 1.5.5 -- https://github.com/rack/rack/blob/1.5.5/lib/rack/deflater.rb#L20
Firstly options were added in the very next release 1.6.0.beta. You can see that here -- https://github.com/rack/rack/blob/1.6.0.beta/lib/rack/deflater.rb#L28
Updating your rack should solve your issue for you

Rails 5: Error when removed quiet_assets_path from development.rb

I have been trying to upgrade my app from Rails 4 to Rails 5. In my Rails 4 version I have quiet_assets_path set but in Rails 5 it is not required. But when I removed that tried to start the server I am getting the following error,
> ruby-2.2.2/gems/rack-mini-profiler-0.10.2/lib/mini_profiler_rails/railtie.rb:93:in
> `>': comparison of Fixnum with nil failed (ArgumentError) from
> /Users/Admin/.rvm/gems/ruby-2.2.2/gems/rack-mini-profiler-0.10.2/lib/mini_profiler_rails/railtie.rb:93:in
> `block in <class:Railtie>'
Can someone help me with this?
Edit:
Following is my rack_profiler.rb,
if Rails.env.development? || Rails.env.production?
require 'rack-mini-profiler'
# initialization is skipped so trigger it
Rack::MiniProfilerRails.initialize!(Rails.application)
Rack::MiniProfiler.config.skip_schema_queries = true
Rack::MiniProfiler.config.skip_paths += %w(/admin/sidekiq)
Rails.application.middleware.delete(Rack::MiniProfiler)
Rails.application.middleware.insert_after(Rack::Deflater, Rack::MiniProfiler)
end
When I comment the delete line then server is starting but if the line uncommented then the server breaks.
thanks for the update. First of all, do you use Rack::Deflater middleware in development environment too?
I think this issue might help you. It basically says that in Rails all delete middleware operations are issued at the end. You can use the swap method as described in the above issue.
If you search the repo issues for "Deflater" you'll find a lot of results, but I believe the above contains your fix.

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

iconv deprecation warning with ruby 1.9.3

I'm getting this warning when I run rspec:
/gems/activesupport-3.1.0/lib/active_support/dependencies.rb:240:in `block in require': iconv will be deprecated in the future, use String#encode instead.
I get the same warning with rails 3.1.0, 3.1.1, 3.1.2.rc2 versions. Seems it's related to sqlite3 gem, but I'm not sure. There are no warnings with ruby 1.9.2
Any suggestions how to deal with it?
You are getting this deprecation notice cause a library somewhere is requiring iconv.
iconv is a gem created by Matz that can be used to convert strings from one format to another.
For example this is often used:
Iconv.iconv('UTF-8//IGNORE', 'UTF-8', content) this little bit of magic takes a UTF-8 string that may have invalid chars and converts it to a proper UTF-8 string.
It has been decided that in Ruby 1.9.3 we should not be using iconv any more and instead use the built-in String#encode. encode is more powerful and allows you more flexibility.
The theory is that the above example could be replaced with:
string.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "?")
In practice it seems this is imperfect.
This also leads to a less than easy story for gem creators who wish to support 1.8:
content = RUBY_VERSION.to_f < 1.9 ?
Iconv.iconv('UTF-8//IGNORE', 'UTF-8', "content") :
"#{content}".encode(Encoding::UTF_8, :invalid => :replace, :undef => :replace, :replace => '')
So, you have a gem somewhere that is requiring iconv, to find it:
Assuming your error message is: /gems/activesupport-3.1.0/lib/active_support/dependencies.rb:240
Open up /gems/activesupport-3.1.0/lib/active_support/dependencies.rb on line 240:
Add the line:
p caller if file =~ /iconv/
(just after: load_dependency(file) { result = super })
You will get a big fat stack trace:
rake --tasks
/home/sam/.rvm/gems/ruby-1.9.3-p125/gems/activesupport-3.2.6/lib/active_support/dependencies.rb:251:in `block in require': iconv will be deprecated in the future, use String#encode instead.
["/home/sam/.rvm/gems/ruby-1.9.3-p125/gems/calais-0.0.13/lib/calais.rb:5:in `'",
.. more omitted ..
This tells me it is the calais gem. Looking through pull requests, I am not the first. The pull has not been yanked in.
Depending on the gem, there may be an upgraded version that does not have this error, so I would recommend you upgrade your gems first. If you are unlucky you may be stuck with the unfortunate task of forking a gem to get rid of this (if for example your pull request to fix it languishes)
If you're seeing this, it's very probably not Rails. If you look at the method surrounding the line being referred to in the error you posted, you'll see the following:
def require(file, *)
result = false
load_dependency(file) { result = super }
result
end
I'm not saying it's your code, necessarily, but I'm certain that it's not actually the line in question where iconv is being called. In my case, I found that my project's code actually contained a reference to iconv.
If you want to check your code for such a reference, try grep -ir iconv ./ in your project directory.
When iconv is actually in a library it can be harder to find. By temporarily changing the above method to:
def require(file, *)
result = false
puts
puts caller.reverse
load_dependency(file) { result = super }
result
end
You can then easily run your code and grep out the relevant lines of the backtrace to find the root cause of the warning.
ruby your/code.rb 2>&1 | grep -B 5 iconv
Add this to the start of your program:
oldverb = $VERBOSE; $VERBOSE = nil
require 'iconv'
$VERBOSE = oldverb
and curse the people who think this is a professional way to handle deprecation.
You can pin down the exact location of the warning by generating exceptions for ActiveSupport::Deprecation, instead of just printing to the log. At the top of application.rb:
ActiveSupport::Deprecation.behavior = Proc.new do |message, backtrace|
raise message
end
Once you've figured out where the warning is coming from (by inspecting the full backtrace), remove this again.
To remove this warning...
go to your .rvm directory and find iconv.c (mine was at ~/.rvm/src/ruby-1.9.3-p125/ext/iconv/iconv.c)
edit that file are remove or comment out the call to warn_deprecated() (should be near the bottom)
from that file's directory, run ruby extconf.rb
then make
then make install
Should do the trick

Resources