Upgraded to Rails 4, and now getting "wrong number of arguments (1 for 2+)" error - ruby-on-rails-4

I recently upgraded my app from Rails 3 to Rails 4, and I'm trying to run the specification tests. Code that I presume used to work just fine (before my time here) suddenly throws an error.
The error:
1) Admin::ReviewsController while logged in #index should get index
Failure/Error: stub_search("product")
ArgumentError:
wrong number of arguments (1 for 2+)
# ./spec/support/searchkick_stub.rb:5:in `stub_search'
# ./spec/controllers/admin/reviews_controller_spec.rb:8:in `block (3 levels) in <top (required)>'
Here is the searchkick_stub.rb:
module SearchkickStub
def stub_search(model)
klass = model.to_s.camelize.constantize
klass.any_instance.stub(:reindex) { true }
klass.stub(:search) do |term, options|
options ||= {}
#search_term ||= term
#search_params ||= options.dup
response = {
'hits' => {
'total' => 0,
'hits' => [],
}
}
result_opts = {
# per Searchkick::Query.new
page: [options[:page].to_i, 1].max,
per_page: (options[:limit] || options[:per_page] || 100000).to_i,
padding: [options[:padding].to_i, 0].max,
load: options[:load].nil? ? true : options[:load],
# per Searchkick::Query.execute
includes: options[:include] || options[:includes],
json: !options[:json].nil?,
}
Searchkick::Results.new(klass, response, result_opts)
end
# Code that reindexes Products will reindex their Inventories too.
stub_search(:inventory) if model == :product
end
end
The signature of stub_search is clearly for a single argument, not two or more like the error claims.
And here is where we use stub_search in reviews_controller_spec.rb
describe ReviewsController do
include SearchkickStub
before do
stub_search(:product)
...
end
end

Figured it out. Per https://github.com/rspec/rspec-rails/issues/941, the issue was the line: require 'minitest/autorun' in spec_helper.rb. This line was added to remove the followig warnings:
Warning: you should require 'minitest/autorun' instead.
Warning: or add 'gem "minitest"' before 'require "minitest/autorun"'
But it turns out that all you need is gem "minitest" in the Gemfile (even though it was already installed, as a dependency for something else, and appeared in Gemfile.lock).

I think the issue comes more from the ruby upgrade. There may have been changes to the interpreter around how block arguments were handled. The search method is stubbed to take 2 arguments in your code: term and options. But it's only invoked with one argument: "product".
options is set to a default value on the first line in that block with options ||= {} so not passing options may not have been a problem with 1.9.3, but with stricter argument checks it breaks in 2.1.5.
A simple fix is to set a default argument in the block arguments, eg.
klass.stub(:search) do |term, options|
to
klass.stub(:search) do |term, options={}|
You can also safely remove the options ||= {} line after doing this.

Related

shoulda validate_inclusion_of not working

Recently upgraded a codebase to rails4 along with gems, now we're getting this error.
Failure/Error: it { is_expected.to ensure_inclusion_of(:usage).in_array(['Index', 'Slide', 'Body']).with_message("%{value} is not a valid usage") }
["Index", "Slide", "Body"] doesn't match array in validation
and here is the related model code
USAGES = ['Index', 'Slide', 'Body']
validates_inclusion_of :usage, :in => USAGES, :message => "%{value} is not a valid usage"
Is there something I'm missing? I don't understand why this is failing.
validate_inclusion_of uses allow_value internally. Admittedly, we should give you a better error message as to what's going on here, but you should be able to write the following tests to figure out what's happening:
it { should allow_value("Index").for(:usage) }
it { should allow_value("Slide").for(:usage) }
it { should allow_value("Body").for(:usage) }
it do
should_not allow_value("something else").
for(:usage).
with_message("%{value} is not a valid usage")
end
My guess is that shoulda-matchers isn't automatically interpolating the %{value} inside of your failure message. If this is true, then what I would do (after filing an issue) is extract the message to an i18n key, and then pass the name of the key to with_message instead.
worked for me -
expect { should validate_inclusion_of(:usage).in?(['a', 'b']) }
should try this -
validates :usage, inclusion: { :in => %w( Index Slide Body ), :message => "%{value} is not a valid usage" }

rails/VCR gem, same URI different method clash

My VCR configure block is:
VCR.configure do |c|
c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
c.hook_into :webmock
c.around_http_request(lambda { |req| req.uri =~ /google.com/ }) do |request|
VCR.use_cassette(request.uri, :decode_compressed_response => true, &request)
end
end
My tests work fine for post/get/put methods but when I try to DELETE, there is a clash in VCR because it matches with a previous PUT request. This is because the URI for that request is the same as the one needed for the DELETE request.
How do I change my use_cassette method so that it uses a combination of URI + method? (or any other suggestion also welcome!)
Thanks!
Solved it, this might help others, so leaving it here:
VCR.use_cassette([request.uri,request.method].join.to_s, :match_requests_on => [:method, :uri], :decode_compressed_response => true, &request)

How do I access sinatra settings in custom extension specs?

I have an email helper extension I have written for my application. I use settings I have defined on the application like so:
set :mailgun_options, JSON.parse(File.open('config/mailer.json').read)[ENV['RACK_ENV']]
which reads configuration settings from a json file into the global Sinatra settings.
I then have my email helper which references these settings to create connections and what not.
require 'sinatra/base'
require 'faraday'
module Sinatra
module EmailHelper
def connect opts={}
connection = Faraday.new(:url => settings.mailgun_options['mailgun_url']) do |faraday|
if settings.mailgun_options['test']
faraday.adapter :test do |stubs|
stubs.post(settings.mailgun_options['domain'] + '/messages') {[ 200, {}, 'success' ]}
end
else
faraday.request :url_encoded
faraday.adapter Faraday.default_adapter
end
end
connection.basic_auth('api', settings.mailgun_options['key'])
return connection
end
def send_email params={}
connect.post((settings.mailgun_options['domain'] + '/messages'), params)
end
def send_password_reset_email email
template = File.open( File.expand_path( '../../helpers/email_helper/templates/password_reset.erb', __FILE__ ), 'r' ).read
send_email({
:from => 'REscour <noreply#' + settings.mailgun_options['domain'] + '>',
:to => email,
:subject => 'REscour.com Password Reset',
:text => ERB.new(template).result(binding)
})
end
end
end
So, when I am trying to write my specs to test the "connect" method, I get the following error:
undefined local variable or method `settings' for #<Class:0x007faaf9c9bd18>
My spec code is as follows:
module Sinatra
describe EmailHelper
let(:dummy_class) { Class.new { extend EmailHelper } }
it 'should connect to mailgun\'s api' do
app.set :mailgun_options, ::JSON.parse(File.open('config/mailer.json').read)['test']
puts dummy_class.connect
end
end
end
I'm not sure how to interact with the global Sinatra settings from my specs to have the local "settings" variable be defined during execution of the helper code.
I could have the architecture of my application wrong here for all I know. Does anyone have any experience in writing Sinatra extensions using the global settings and write specs for them?
The spec you've written seems to want to be a unit test, because you've not run the extension the way it would be used in an app. In the specs, try something like:
describe "connect" do
let(:app) { Sinatra.new do
helpers Sinatra::EmailHelper
configure do
:mailgun_options, ::JSON.parse(File.open('config/mailer.json')
end
get "/" do
connect
end
end
}
# now write specs for the `connect` helper
end
Using an anonymous class (Sinatra.new do…) lets you quickly set up an app that's convenient for a small test, but there are other ways too.
In the extension, you need to add:
helpers EmailHelper
as per the example in the docs.

Quick Multiple calls to Firebase crashes Rails

My controller pushes data to firebase on certain clicks.
class FirebaseController < ApplicationController
Firebase.base_uri = "https://firebaseProject.Firebaseio.com/"
def call_to_firebase
Firebase.push("firebase_channel", "firebase_data".to_json)
respond_to do |format|
format.json { render nothing: true, :status => 204 }
end
end
end
In case of quick successive calls to this controller, which is called on a click, my Puma server crashes immediately.
I am using Rails 4.0.0
Puma 2.6.0
Ruby 2.0.0
Below is a part of the huge log report generated.
ETHON: started MULTI
ETHON: performed EASY url= response_code=200 return_code=got_nothing total_time=2.663048
/Users/siddharthbhagwan/.rvm/gems/ruby-2.0.0-p247/gems/ethon-0.6.1/lib/ethon/multi/operations.rb:171: [BUG] Segmentation fault
ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.3.0]
-- Crash Report log information --------------------------------------------
See Crash Report log file under the one of following:
* ~/Library/Logs/CrashReporter
* /Library/Logs/CrashReporter
* ~/Library/Logs/DiagnosticReports
* /Library/Logs/DiagnosticReports
the more detail of.
-- Control frame information -----------------------------------------------
c:0091 p:---- s:0489 e:000488 CFUNC :multi_perform
c:0090 p:0018 s:0484 e:000483 METHOD /Users/siddharthbhagwan/.rvm/gems/ruby-2.0.0-p247/gems/ethon-0.6.1/lib/ethon/multi/operations.rb:171
c:0089 p:0034 s:0479 e:000478 METHOD /Users/siddharthbhagwan/.rvm/gems/ruby-2.0.0-p247/gems/ethon-0.6.1/lib/ethon/multi/operations.rb:160
c:0088 p:0036 s:0474 e:000473 METHOD /Users/siddharthbhagwan/.rvm/gems/ruby-2.0.0-p247/gems/ethon-0.6.1/lib/ethon/multi/operations.rb:43
c:0087 p:0020 s:0470 e:000469 METHOD /Users/siddharthbhagwan/.rvm/gems/ruby-2.0.0-p247/gems/typhoeus-0.6.6/lib/typhoeus/hydra/runnable.rb:21
c:0086 p:0008 s:0466 e:000465 METHOD /Users/siddharthbhagwan/.rvm/gems/ruby-2.0.0-p247/gems/typhoeus-0.6.6/lib/typhoeus/hydra/memoizable.rb:51
c:0085 p:0104 s:0463 e:000462 METHOD /Users/siddharthbhagwan/.rvm/gems/ruby-2.0.0-p247/gems/firebase-0.1.4/lib/firebase/request.rb:50
c:0084 p:0019 s:0456 e:000455 METHOD /Users/siddharthbhagwan/.rvm/gems/ruby-2.0.0-p247/gems/firebase-0.1.4/lib/firebase/request.rb:20
c:0083 p:0019 s:0451 e:000450 METHOD /Users/siddharthbhagwan/.rvm/gems/ruby-2.0.0-p247/gems/firebase-0.1.4/lib/firebase.rb:34
.
.
.
c:0005 p:0027 s:0029 e:000028 METHOD /Users/siddharthbhagwan/.rvm/gems/ruby-2.0.0-p247/gems/puma-2.6.0/lib/puma/server.rb:357
c:0004 p:0035 s:0022 e:000021 BLOCK /Users/siddharthbhagwan/.rvm/gems/ruby-2.0.0-p247/gems/puma-2.6.0/lib/puma/server.rb:250 [FINISH]
c:0003 p:---- s:0016 e:000015 CFUNC :call
c:0002 p:0084 s:0011 e:000010 BLOCK /Users/siddharthbhagwan/.rvm/gems/ruby-2.0.0-p247/gems/puma-2.6.0/lib/puma/thread_pool.rb:92 [FINISH]
c:0001 p:---- s:0002 e:000001 TOP [FINISH]
.
.
.
[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html
Abort trap: 6
By quick I mean one click per second. This doesnt happen for slower clicks like 1 click per 2 seconds.
Pushing to firebase from the irb in a loop doesn't cause this error.
Thanks in Advance,
Cheers!
Are you using firebase-ruby gem? I submitted a bug fix for this issue today. You can hot patch it yourself by overriding the problematic method in the gem like so:
module Firebase
class Request
def process(method, path, body=nil, query_options={})
request = Typhoeus::Request.new(build_url(path),
:body => body,
:method => method,
:params => query_options)
response = request.run
Firebase::Response.new(response)
end
end
end
Or wait for the pull request to be accepted. The problem was in the gem's use of Typheous' Hydra.

How to generate JavaDoc using buildr?

I want to automatically generate the JavaDoc using buildr. I tried using the approach suggested in the official Guide PDF from the Homepage. However, it did not work.
define "SharedState_ebBP", :layout=>eclipse_layout do
project.version = VERSION_NUMBER
project.group = GROUP
doc :windowtitle => "Abandon All Hope, Ye Who Enter Here", :private => true
end
The error message is as follows:
RuntimeError: Don't know how to generate documentation from windowtitleAbandon ......
The correct syntax for setting the window title is
doc.using(:windowtitle => "Abandon All Hope", :private => true)
and with end on a line by itself. However that in and of itself does not cause the doc task to get run automatically.
To automatically build the JavaDoc when you run buildr simply add to the end of your buildfile:
task :default => [:build, :doc]
This redefines the default task to first build and then doc.