Activesupport / Multi json: "Did not recognize your adapter specification" - ruby-on-rails

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.

Related

ArgumentError when running Capybara tests on Ruby 3.0

I am really stuck. I am upgrading my Rails app to Ruby 3 (from 2.7). When running tests, I always run into this issue when I visit a path:
state = "new"
visit status_path(state: “state")
I receive the following error when running rspec:
Capybara starting Puma...
* Version 5.6.4 , codename: Birdie's Version
* Min threads: 0, max threads: 4
* Listening on http://127.0.0.1:58568
ArgumentError: wrong number of arguments (given 2, expected 1)
from ~/.rbenv/versions/3.0.5/lib/ruby/3.0.0/net/protocol.rb:116:in `initialize'
My Gemfile is as such:
gem "capybara" # 3.38.0
gem "selenium-webdriver" # 4.8.0
gem "webdrivers" # 5.2.0
(They're all on the latest version)
My setup doesn't look wrong:
require "webdrivers/chromedriver"
Webdrivers.cache_time = 86_400 # 1 day
Capybara.register_driver :headless_chrome do |app|
Capybara::Selenium::Driver.load_selenium
browser_options = ::Selenium::WebDriver::Chrome::Options.new.tap do |options|
options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-gpu")
end
Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
end
Capybara.javascript_driver = :headless_chrome
Troubleshooting:
I tried Puma 6 - same issue.
The controllers at status_path is not even hit. This errors occurs right after Puma loads up.
I do not think it's the Capybara setup, and I just cannot find where it is calling the Ruby 3 library wrong (net/protocol).
I downgraded capybara to 3.37.1, and same issue.
Thank you
FYI Upgrading from 2.7 to 3 you will more often than not see this error. It's highly likely that some code you were previously using in 2.7 will be not correctly hashing some args.
The first hit when googling this will take you back to SO (Won't share link as SO doesn't like links). But to paraphrase from the official ruby byline when updating
Separation of positional and keyword arguments in Ruby 3.0:
In most cases, you can avoid incompatibility by adding the double splat operator. It explicitly specifies passing keyword arguments instead of a Hash object. Likewise, you may add braces {} to explicitly pass a Hash object, instead of keyword arguments.
TL;DR - Try doing splatting your hash args collection kwargs -> **kwargs - Your rails path likely isn't a kwarg but a hash --> { key: value }
EDIT: Reasoning (If you're interested), is that prior to ruby3. Ruby would try assess and guesstimate what you meant. From ruby3 onwards it has made a change and fill forcibly use what you give it (A lot of people used to use kwargs but wanted them treated as a single hash, now you need to stipulate this!)

otp_code: wrong number of arguments in recent update of active_model_otp gem

I updated my Gemfile and rotp (4.1.0) and active_model_otp(1.2.0) gems got updated. Since then I've start getting error while calling #user.otp_code method associated with User modal "wrong number of arguments (given 2, expected 1)"
/usr/local/lib/ruby/gems/2.3.0/gems/rotp-4.1.0/lib/rotp/totp.rb:17:in `at'
/usr/local/lib/ruby/gems/2.3.0/gems/active_model_otp-1.2.0/lib/active_model/one_time_password.rb:77:in `otp_code'
/home/app/controllers/api/v1/users_controller.rb:745:in `resetpassword'
as far as I dig into it, I found this.
the issue is in arguments, it seems the latest rotp gem have updated below method to accept only 1 argument insted of 2 as compared to older version (3.3.1)
since the optional parameter has been removed, the active_model_otp-1.2.0 gem is giving error at line number 77
as per rotp-4.1.0
def at(time)
generate_otp(timecode(time))
end
as per rotp-3.3.1
def at(time, padding=true)
unless time.class == Time
time = Time.at(time.to_i)
end
generate_otp(timecode(time), padding)
end
I tried making changes in the gem as below
def otp_code(options = {})
if otp_counter_based
if options[:auto_increment]
self.otp_counter += 1
save if !new_record?
end
ROTP::HOTP.new(otp_column, digits: otp_digits).at(self.otp_counter)
else
if options.is_a? Hash
time = options.fetch(:time, Time.now)
padding = options.fetch(:padding, true)
else
time = options
padding = true
end
# ROTP::TOTP.new(otp_column, digits: otp_digits).at(time, padding)
# -- Commented Above Line to remove padding arguments from it.
ROTP::TOTP.new(otp_column, digits: otp_digits).at(time)
end
end
it worked but not sure what else will break, active-model gem was last updated in 2015, and rotp updated few months back.
please suggest suitable method, if I revert back to previous gem version of rotp then what else would break. I'm kind of stuck.
kindly help.
Looks like if you want to use active_model_otp gem you'll have to downgrade rotp as suggested in the opened issue. Not sure if it breaks anything, probably it won't since it worked previously for you.
Seems like they don't rush to fix it, perhaps you can create a PR with a fix so that maybe they accept it.
Another option is to fork their repo, fix it and publish as your own gem to use it instead.
I could resolve the above issue by locking the rotp gem to 3.3.1 version.
Steps to Follow:
1) Update gem file with
gem 'rotp', '~> 3.3.0'
2) Take a backup of Gemfile.lock to Gemfile-backup-xx-xx-xxx.lock
3) run bundle install.

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.

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

Rails + Ruby 1.9 "invalid byte squence in US-ASCII"

After upgrading to ruby 1.9 we began to notice pages failing to render from the rails template renderer when a user used a non-ASCII character. Specifically "é". I was able to resolve this issue on one of our staging servers, but I have not been able to reproduce the fix on our production server.
The fix that seemed to work the first time:
Converted the database from latin1 to utf8 using the convert_charset tool available here: http://www.mysqlperformanceblog.com/2009/03/17/converting-character-sets/. (including setting default_character_set=utf8 in my.cnf and running SET GLOBAL character_set_server=utf8
Switched to the sam-mysql-ruby adapter (instead of the standard mysql adapter: http://gemcutter.org/gems/sam-mysql-ruby)
Restarted rails
The error is:
"invalid byte sequence in US-ASCII"
Oddly, after following the steps above the error has not changed on our production server. Setting encoding: utf8 in database.yml does not change the error either.
The error raised on the following line of code:
<%= link_to h(question.title), question_path(question) %>
This blog seems to suggest a fix, but it mentions that this should not be a problem in 1.9: http://www.igvita.com/2007/04/11/secure-utf-8-input-in-rails/ (and it's over 2 years old).
I imagine this problem might soon affect a lot of people as more rails developers people switch to 1.9.
I found the solution:
The problem is:
Fetching data from any database (Mysql, Postgresql, Sqlite2 & 3), all configured to have UTF-8 as it's character set, returns the data with ASCII-8BIT in ruby 1.9.1 and rails 2.3.2.1.
(Taken from: https://rails.lighthouseapp.com/projects/8994/tickets/2476)
My attempt to use the patched mysql adapter likely failed because my database was not configured to natively use utf8, so the patched adapter failed to work properly.
The fix ended up being to use the patch file available here: http://gnuu.org/2009/11/06/ruby19-rails-mysql-utf8/
require 'mysql'
class Mysql::Result
def encode(value, encoding = "utf-8")
String === value ? value.force_encoding(encoding) : value
end
def each_utf8(&block)
each_orig do |row|
yield row.map {|col| encode(col) }
end
end
alias each_orig each
alias each each_utf8
def each_hash_utf8(&block)
each_hash_orig do |row|
row.each {|k, v| row[k] = encode(v) }
yield(row)
end
end
alias each_hash_orig each_hash
alias each_hash each_hash_utf8
end
(Placed in lib/mysql_utf8fix.rb and required in enviornment.rb using require 'lib/mysql_utf8fix.rb')
it is only require 'mysql_utf8fix.rb' (rails 2.3.11)
Please user mysql2(gem) adapter instead of mysql adapter in database.yml
and remove the mysql patches(If exists) and add the following lines in environment.rb.
Encoding.default_external = Encoding::UTF_8
Encoding.default_internal = Encoding::UTF_8
Then run in apache and passenger it ll work fine
Thanks,
Ramanavel Selvaraju.

Resources