Getting server error 500 on calling a method ruby - ruby

When I call a function I get the following error log;
please help decipher it.
NoMethodError (undefined method `first' for #<Matching:0x0000000875a050>):
app/mailers/matching_mailer.rb:6:in `new_matchings_for_customer'
app/models/matching.rb:133:in `block in create_matchings_from_service'
app/models/matching.rb:126:in `each'
app/models/matching.rb:126:in `create_matchings_from_service'
app/models/matching.rb:30:in `process_matchings_for_service'
app/models/payments/subscription.rb:94:in `find_matchings'
app/models/payments/subscription.rb:85:in `after_create_actions'
app/controllers/contractors/subscriptions_controller.rb:51:in `subscribe'
app/controllers/contractors/subscriptions_controller.rb:19:in `create'
EDIT 1:
First few lines of matching mailer:
class MatchingMailer < ActionMailer::Base
default from: "\"Estimate My Project\" <info#estimatemyproject.com>"
def new_matchings_for_customer(matchings, customer_id)
#customer = Customer.find(customer_id)
#matchings = Matching.find(matchings)
#category = #matchings.first.emp_request.subcategory.category
unless #customer.email.empty?
mail(to: #customer.email, subject: "#{#category.name} estimate for project in #{#customer.zip_code.county.name}, #{#customer.zip_code.state.code} #{#customer.zip_code.code}")
else
self.message.perform_deliveries = false
end
end

NoMethodError (undefined method `first' for #<Matching:0x0000000875a050>)
means that there is no method first on a Matching.
app/mailers/matching_mailer.rb:6:in `new_matchings_for_customer'
means you try to call the method first on an instance of matching in line 6 of the `app/mailers/matching_mailer.rb``
Looking at your MatchingMailer in line 6, we see hat you call first on #matching. #matching was set just the line before. Please note that the Matching.find returns one record when you pass in a single id and returns an array of records when you pass in a array of ids. In this case you pass matchings that was provided as an argument to the new_matchings_for_customer method.
It is quite obvious, that the matchings argument must be a single id. Otherwise #matchings would have return an array and an array would respond to first. Since you always call first and never care about other values in the array, it makes more sense to just load one record.
Change your MatchingMailer to:
class MatchingMailer < ActionMailer::Base
default from: '"Estimate My Project" <info#estimatemyproject.com>'
def new_matchings_for_customer(matching_id, customer_id)
customer = Customer.find(customer_id)
if customer.email.present?
matching = Matching.find(matching_id)
category = matching.emp_request.subcategory.category
mail(
to: customer.email,
subject: "#{category.name} estimate for project in #{customer.zip_code.county.name}, #{customer.zip_code.state.code} #{customer.zip_code.code}"
)
else
self.message.perform_deliveries = false
end
end
end
And ensure to only pass one matching_id when calling that method.

Related

Ruby - no implicit conversion of Array into String

I am getting an error when executing my test.
Failure/Error: expect(industry_sic_code).to include page.sic_code
TypeError:
no implicit conversion of Array into String
# ./spec/os/bal/company/company_filter_clean_harbors_industries_stub.rb:62:in `block (2 levels) in <top (required)>'
The Method:
def sic_code
subtables = #b.table(:class => 'industry-codes').tables(:class => 'industry-code-table')
subtables.each do |subtable|
if subtable.tbody.h4.text == "US SIC 1987:"
subtable.tr.next_siblings.each do |tr|
codes = tr.cell
puts codes.text.to_s
end
end
end
end
The Test:
it 'Given I search for a random Clean Harbors Industry' do
#Pick a random clean industry from the file
data = CSV.foreach(file_path, headers: true).map{ |row| row.to_h }
random = data.sample
random_industry = random["Class"]
industry_sic_code = random["SIC Code"]
end
it 'Then the result has the expected SIC code' do
page = DetailPage.new(#b)
page.view
expect(industry_sic_code).to include page.sic_code
end
I have tried to implicitly change each variable to a string but it still complain about the array issue.
When I include some puts statments, I get some really wonky responses. The method itself returns the expected result.
When I used the method in the test I end up with the code gibberish below.
here are the sic codes from the method
5511
Here are the codes from the test
#<Watir::Table:0x00007fa3cb23f020>
#<Watir::Table:0x00007fa3cb23ee40>
#<Watir::Table:0x00007fa3cb23ec88>
#<Watir::Table:0x00007fa3cb23ead0>
#<Watir::Table:0x00007fa3cb23e918>
#<Watir::Table:0x00007fa3cb23e738>
#<Watir::Table:0x00007fa3cb23e580>
Your sic_code method returns subtables array, that's why you have this error. It doesn't matter that the method puts something, every method in ruby implicitly returns result of its last line, in your case it is subtables.each do ... end, so you have an array.
You need to explicitly return needed value. Not sure if I correctly understood what are you doing in your code, but try something like this:
def sic_code
subtables = #b.table(:class => 'industry-codes').tables(:class => 'industry-code-table')
result = [] # you need to collect result somewhere to return it later
subtables.each do |subtable|
if subtable.tbody.h4.text == "US SIC 1987:"
subtable.tr.next_siblings.each do |tr|
codes = tr.cell
result << codes.text.to_s
end
end
end
result.join(', ')
end

Sinatra: params hash cannot be merged

I want to merge a hash with default parameters and the actual parameters given in a request. When I call this seemingly innocent script:
#!/usr/bin/env ruby
require 'sinatra'
get '/' do
defaults = { 'p1' => 'default1', 'p2' => 'default2' }
# params = request.params
params = defaults.merge(params)
params
end
with curl http://localhost:4567?p0=request then it crashes with
Listening on localhost:4567, CTRL+C to stop
2016-06-17 11:10:34 - TypeError - no implicit conversion of nil into Hash:
sinatrabug:8:in `merge'
sinatrabug:8:in `block in <main>'
When I access the Rack request.params directly it works. I looked into the Sinatra sources but I couldn't figure it out.
So I have a solution for my actual problem. But I don't know why it works.
My question is: Why can I assign param to a parameter, why is the class Hash but in defaults.merge params it throws an exception?
Any idea?
This is caused by the way Ruby handles local variables and setter methods (i.e. methods that end in =) with the same name. When Ruby reaches the line
params = defaults.merge(params)
it assumes you want to create a new local variable named params, rather than use the method. The initial value of this variable will be nil, and this is the value that the merge method sees.
If you want to refer to the method, you need to refer to it as self.params=. This is for any object that has such a method, not just Sinatra.
A better solution, to avoid this confusion altogether, might be to use a different name. Something like:
get '/' do
defaults = { 'p1' => 'default1', 'p2' => 'default2' }
normalized_params = defaults.merge(params)
normalized_params.inspect
end
Your code is throwing an error because params is nil when you make this call defaults.merge(params). I assume you are trying to merge defaults with request.params, which should contain the parameters from your GET.
Change this line
params = defaults.merge(params)
to this
params = defaults.merge(request.params)
I found this in rack gem
http://www.rubydoc.info/gems/rack/Rack/Request#params-instance_method
It seems you can retrieve GET and POST data by params method but you can't write in it. You have to use update_param and delete_param instead.

Ruby Rspec cucumber array each do

I have scenario when upon login to the page, I am presented with numerous profile(can be 1 to 5).
I am looking for specific profile based by tn number.
I locate element that represent tn and then put in array to search for all available elements with same to locate correct profile in order to click on it.
Here is the code:
And(/^I look for "([^"]*)"$/) do |number|
elements = #driver.find_elements(:css => "h3.phone-number")
elements.each do |element|
renewals_page.select_profile.click if element.text == #config[number]
return element
end
fail
end
I am passing desired number from yaml file depends on the account.
renewals_page.select_profile.click is defined in another file as method
def select_profile
#driver.find_element(:css => "h3.phone-number")
end
So when I try to locate that element and click on it, I get following error
unexpected return (LocalJumpError)
./features/step_definitions/renewals_login_step.rb:28:in `block (2 levels) in <top (required)>'
./features/step_definitions/renewals_login_step.rb:26:in `each'
./features/step_definitions/renewals_login_step.rb:26:in `/^I look for "([^"]*)"$/'
Remove return from here:
renewals_page.select_profile.click if element.text == #config[number]
# ⇓⇓⇓⇓⇓⇓
# return element # removed
element # proper working return from lambda: result of last line
end
the reason is that return keyword may be used to return from method only, not from lambda.

NoMethodError (undefined method `[]' for nil:NilClass)

I have a very odd instance of this error:
NoMethodError (undefined method `[]' for nil:NilClass):
app/controllers/main_controller.rb:150:in `block in find_data_label'
app/controllers/main_controller.rb:149:in `each'
app/controllers/main_controller.rb:149:in `find_data_label'
app/controllers/main_controller.rb:125:in `data_string'
app/controllers/main_controller.rb:35:in `catch'
Whats weird is that the line 150, where it says the error is, is inside a loop and executes perfectly 11 times before it decides to error out. I am out of ideas as to why it would work fine but fail one line before what would effective be the loop where the if statement returns true.
This is the code:
def find_data_label(label)
#fields.each do |f|
puts "f[:field_data]['Title'] = #{f[:field_data]['Title']}" # <--- line 150
if f[:field_data]['Title'] == label
return f
end
end
end
And this is the output before I get the error:
f[:field_data]['Title'] = Name
f[:field_data]['Title'] = Name
f[:field_data]['Title'] = Mobile number
f[:field_data]['Title'] = Email
f[:field_data]['Title'] = Date of birth
f[:field_data]['Title'] = Gender
f[:field_data]['Title'] = Street name
f[:field_data]['Title'] = Street number
f[:field_data]['Title'] = My local Puckles store is in
f[:field_data]['Title'] = Suburb
f[:field_data]['Title'] = Postcode
Completed 500 Internal Server Error in 2047ms
Thanks in advance for any help.
One of your #fields elements doesnt contain Title in :field_data.
Try inspecting #fields before calling #fields.each:
Rails.logger.warn '-'*40
Rails.logger.warn #fields.inspect
Check the server logs to see what elements you have in #fields.
For that error, see also: http://mongoid.org/en/mongoid/docs/tips.html
e.g. maybe you're using MongoID and an older version of Ruby.

How do I handle the wrong number of method arguments?

I'm working on a URL shortener and attemtping to convert the URL ID, which is a number, into a string, using base 36.
I'm receiving the error listed below the code:
def self.create_link(original)
url = Url.create(:original => original)
if Link.first(:indentifier => url.id.to_s(36)).nil? or !DIRTY_WORDS.include? url.id.to_s(36)
link = Link.new(:identifier => url.id.to_s(36))
link.url = url
link.save
return link
else
create_link(original)
end
end
I'm receiving the following error:
wrong number of arguments(1 for 0) file: tinyclone.rb location: to_s line: 91
When I researched the error, I found someone who mentioned that this error is common when you attempt to pass in parameter values when a method doesn't accept them. The error is specifically referring the following line.
if Link.first(:indentifier => url.id.to_s(36)).nil? or !DIRTY_WORDS.include? url.id.to_s(36)
What's the type of url.id?
I think your expecting it to be a FixNum whose to_s method accepts a radix, but you're getting something else instead... maybe a string containing a number? (e.g. "1234")
Anyway, the method seems to require no arguments and you are passing 36 nevertheless
EDIT:
Can't find the reference to the class you pointed out (Serial), but this might be worth a try:
url.id.to_i.to_s(36)
One thing I see right away is:
if Link.first(:indentifier => url.id.to_s(36)).nil? or !DIRTY_WORDS.include? url.id.to_s(36)
link = Link.new(:identifier => url.id.to_s(36))
Notice that in the first line you have :indentifier and in the second it's :identifier.
Otherwise, I agree with #Pablo Fernandez's answer that it's probably tied to the type of id.
you have 2 models, but take full responsibility on the one of them only. please take a look at code separated logic:
# Link model
def self.create_link(original)
url = Url.create(:original => original)
url_id = url.encoded_id
find_or_create_by_identifier!(:identifier => url_id)
end
# Url model
def before_validate_on_create
if url.id.to_s.include? DIRTY_WORDS
self.errors.add(:base, 'the url is invalid')
end
end
def encoded_id
url.id.to_s(36)
end

Resources