Cant found model with out an ID in rails 3.2.12 - ruby-on-rails

i ve this method. I m not at all able to understand the error which is
Couldn't find Company without an ID
in ActiveRecord::RecordNotFound in CustomersController#bulk_create
This method is written to create customers for a company in bulk by taking their name and numbers in format name:number.
The method is as follows:
def bulk_create
res = ""
comp_id = params[:customer][:selected_companies].delete_if{|a| a.blank?}.first
comp = Company.find(comp_id)
s = SentSmsMessage.new
s.set_defaults
s.data = tmpl("command_signup_ok", customer, comp) unless params[:customer][:email].length > 0
s.data = params[:customer][:email] if params[:customer][:email].length > 0
s.company = comp if !comp.nil?
s.save
unless comp_id.blank?
params[:customer][:name].lines.each do |line|
(name, phone) = line.split(/\t/) unless line.include?(":")
(name, phone) = line.split(":") if line.include?(":")
phone = phone.gsub("\"", "")
phone = phone.strip if phone.strip.to_i > 0
name = name.gsub("\"", "")
name = name.gsub("+", "")
phone = "47#{phone}" if params[:customer][:active].to_i == 1
customer = Customer.first(:conditions => ["phone_number = ?", phone])
if customer.nil?
customer = Customer.new
customer.name = name
# customer.email
# customer.login
# customer.password
customer.accepted_agreement = DateTime.now
customer.phone_number = phone
customer.active = true
customer.accepted_agreement = DateTime.now
customer.max_msg_week = params[:customer][:max_msg_week]
customer.max_msg_day = params[:customer][:max_msg_day]
customer.selected_companies = params[:customer][:selected_companies].delete_if{|a| a.blank?}
res += "#{name} - #{phone}: Create OK<br />" if customer.save
res += "#{name} - #{phone}: Create failed<br />" unless customer.save
else
params[:customer][:selected_companies].each do |cid|
new_company = Company.find(cid) unless cid.blank?
if !new_company.nil?
if !customer.companies.include?(new_company)
customer.companies << new_company
if customer.save
res += "#{name} - #{phone}: Customer exists and the customer was added to the firm #{new_company.name}<br />"
else
res += "#{name} - #{phone}: Customer exist, but something went wrong during storage. Check if the client is in the firm.<br />"
end
else
res += "#{name} - #{phone}: Customer exists and is already on firm #{new_company.name}<br />"
end
end
end
end
s.sms_recipients.create(:phone_number => customer.phone_number)
end
s.save
s.send_as_sms
#result = res
respond_to do |format|
format.html { render "bulk_create"}
end
else
#result = "You have not selected any firm to add these users. Press the back button and try again."
respond_to do |format|
format.html { render "bulk_create"}
end
end
end
I want to update one situation here. That when i submit the form blank then it gives this error. Also if i filled the form with the values then its show the situation which the method is returning in case of fail.
res += "#{name} - #{phone}: Create failed <br />"
The tmpl method
private
def tmpl(setting_name, customer, company = nil)
text = ""
if customer.companies.count > 0
sn = "#{setting_name}_#{#customer.companies.first.company_category.suffix}".downcase rescue setting_name
text = Setting.value_by(sn) rescue ""
end
textlenth = text.length rescue 0
if textlenth < 3
text = Setting.value_by(setting_name) rescue Setting.value_by("command_error")
end
return fill_template(text, customer, company)
end
From the model customer.rb
def selected_companies=(cmps)
cmps.delete("")
# Check the old ones. Make a note if they are not in the list. If the existing ones are not in the new list, just remove them
self.companies.each do |c|
self.offer_subscriptions.find(:first, ["customer_id = ?", c]).destroy unless cmps.include? c.id.to_s
cmps.delete c.id.to_s if cmps.include? c.id.to_s
end
# Then create the new ones
cmps.each do |c2|
cmp = Company.find(:first, ["id = ?", c2])
if cmp && !c2.blank?
offerSubs = offer_subscriptions.new
offerSubs.company_id = c2
offerSubs.save
end
end
end
def selected_companies
return self.companies.collect{|c| c.id}
end
The association of customer is as follows:
has_many :offer_subscriptions
has_many :companies, :through => :offer_subscriptions
This code is written by the some one else. I m trying to understand this method but so far not being able to understand this code.
Please help.
Thanks in advance.

You are getting 'Couldn't find Company without an ID' error because your Company table doesn't contain record with id = comp_id
Change comp = Company.find(comp_id) to comp = Company.find_by_id(comp_id).
This will return nil instead of an error.
Add comp is not nil condition is already handled in your code.

Your comp_id line is returning nil.
comp_id = params[:customer][:selected_companies].delete_if{|a| a.blank?}.first
Post the params that get passed to this function and we could hopefully find out why. In the meantime you could enclose the block in a begin - rescue block to catch these errors:
begin
<all your code>
rescue ActiveRecord::RecordNotFound
return 'Unable to find a matching record'
end

try this:
comp = ""
comp = Company.find(comp_id) unless comp_id.nil?
instead of comp = Company.find(comp_id)
further nil checking present in your code.

Reason being
params[:customer][:selected_companies].delete_if{|a| a.blank?} = []
so [].first = nil
therefor, params[:customer][:selected_companies].delete_if{|a| a.blank?}.first = nil
and comp_id is nil
So check the log file and check what is coming in the parameter "selected_companies"
when you will find the parameter, everything will be understood well....

Related

How does recalling a variable work in a method?

I have the following method:
vendor_orders = VendorOrder.where(id: params[:vendor_order_ids])
orders = Order.find(vendor_orders.pluck(:order_id))
products = Product.joins(:vendor_product).where(vendor_products:{vendor_id: current_user.id }).ids #get all vendor_products that match current_user.vendor
line_items = LineItem.joins(:shop_product).where(cart_id: orders.pluck(:cart_id), fulfillment_status: "processing", shop_products: {product_id: products}).where.not(fulfillment_status: "canceled")
messages = []
n = 0
puts "line items: #{line_items.count}" #puts out 1
line_items.map do |li|
if li.update_attribute(:fulfillment_status, params[:mass][:fulfillment_status])
n+=1
else
messages << "#{vendor_order.vendor_order_token}"
end
end
puts "line items2: #{line_items.count}" #puts out 0
if n == line_items.count
flash.keep[:notice] = "Update for #{vendor_orders.count} order(s) and #{n} product(s) successful"
else
flash.keep[:notice] = "Failed update for Order: #{messages.join if messages.any?}"
end
puts "line item3 #{line_items.count}" #puts out 0
respond_to do |format|
format.html { redirect_to vendor_orders_path }
end
The question i have is about the puts
When calling line_items.count after I update the line_items to then not match the variable, does it recall line_items from above?
Is this true? I always assumed once something was defined and passed, it would stay at the rate, unless redefined.
Marek solved the issue by letting me know .count is a call to the database which will then call what you defined previously.
To solve this, I just use line_items_count = line_items.count and use that above any alterations to check against it.

Rails does not write column

i have a totally strange problem:
Rails 6.0.0
ruby 2.5.7
mysql 8.0.15
it saves the most columns, but not all.
p.errors.full_messages delivers emtpy array and p.valid? delivers true.
but, p.to_geocode does not be set to true in the database, p.location_string is also not saved.
But, all the values, which are advised by the loop (hash.keys.each {..) are correctly stored.
what may there be?
thanks in advance!
Chris
Code:
def write_project(hash)
# MAKE RECORD
p = Project.new
hash.keys.each {|k| p[k.to_sym] = hash[k.to_sym]}
p.created_by = session[:login_name]
p.group = 'antenna_project'
#default_values.each do |k, v|
unless p[k.to_sym].present?
p[k.to_sym] = v
end
end
p.import_id = #import.id
# ERROR HANDLING SAVE
p[:to_geocode] = true
p.location_string = [hash[:street].to_s, hash[:zip].to_s, hash[:city].to_s, 'switzerland'].reject(&:empty?).join(', ')
unless p.save(validate: false)
e = "COULD NOT SAVE RECORD"
log_import_error(nil, e)
return e
end
#import.block_others_until = (DateTime.now + 1.seconds)
#import.save
return "SUCCESS"
end

Screen Scraping with nokogiri

I am a full stack ruby developer.I am trying to scrape to the data from the website and i am successfully able to get the data.But the problem is that next time when i fetched the data i just want to fetch only new data the i don't want to overwrite all the the data in the database.
I just want to add new record which added recently.But i am not able to find any solution for that how to do it with minimum queries and minimum code.
Here is my code which i am using for scrapping:
client = Mechanize.new
index_page = client.get('https://www.google.com/')
document_page_index = Nokogiri::HTML::Document.parse(index_page.body)
page_no_merchant = document_page_index.css('.pagination.pagination-centered ul li:nth-last-child(2) a').text.to_i
1.upto(page_no_merchant) do |page_number|
client.get("https://www.google.com/buy-gift-cards?page=#{page_number}") do |page|
document = Nokogiri::HTML::Document.parse(page.body)
document.css('.product-source').each do |item|
merchant_name= item.children.css('.name').text.gsub("Gift Cards", "")
puts merchant_name
href = item.css('a').first.attr('href')
puts href
image_url=item.children.css('.img img').attr('data-src').text.strip
puts image_url
image_url=URI.parse(image_url)
#merchant=Merchant.create!(name: merchant_name , image_url:image_url)
first_page = client.get("https://www.google.com#{href}")
document_page = Nokogiri::HTML::Document.parse(first_page.body)
page_no = document_page.css('.pagination.pagination-centered ul li:nth-last-child(2) a').text.to_i
1.upto(page_no) do |page_number_giftcard|
type1=[]
card_page = client.get("https://www.google.com#{href}?page=#{page_number_giftcard}")
document_page = Nokogiri::HTML::Document.parse(card_page.body)
document_page.xpath('//table/tbody/tr[#class="toggle-details"]').collect do |row|
row.at("td[2] ul").children.each do |typeli|
type = typeli.text.strip if typeli.text.strip.length != 0
type1 << type if typeli.text.strip.length != 0
end
value = row.at('td[3]').text.strip
value = value.to_s.tr('$', '').to_f
puts value
per_discount = row.at('td[4]').text.strip
per_discount = per_discount.to_s.tr('%', '').to_f
puts per_discount
final_price = row.at('td[5] strong').text.strip
final_price = final_price.to_s.tr('$', '').to_f
puts final_price
puts '******************************'
#giftcard=Giftcard.create(card_type:1, card_value:value, per_off:per_discount, card_price: final_price, merchant_id: #merchant.id)
end
#giftcard.update_attribute()
end
end
end
end
Thank you in advance.
Basically you are saving all data, by doing this.
#merchant=Merchant.create!(name: merchant_name , image_url:image_url)
You can try something like find_or_create_by.
#merchant=Merchant.find_or_create_by(name: merchant_name , image_url:image_url)
http://apidock.com/rails/v4.0.2/ActiveRecord/Relation/first_or_create
http://apidock.com/rails/v4.0.2/ActiveRecord/Relation/find_or_create_by

Ruby each block next when exception or error is raised

I have the following method in my rake task.
def call
orders = Spree::Order.complete.where('completed_at >= :last_day', last_day: Time.now - 30.days)
orders.each do |order|
order_tracking = order.shipments.first.tracking
next if order_tracking.nil?
shipment = order.shipments.first
results = fedex.track(tracking_number: order_tracking)
tracking_info = results.first
status = tracking_info.status.to_s
delivery_date = tracking_info.delivery_at
shipment.is_delivered = delivered?(status)
shipment.date_delivered = delivery_date
shipment.save
puts "-> Shipping status was updated for #{order.number}"
end
end
If there is an order with no tracking number I skipping it with next on line 5.
My question: How would I do next if a tracking number is invalid and the following error is raised:
Fedex::RateError: Invalid tracking number.
Ideally I would like to change line 5 to:
next if order_tracking.nil? || order_tracking.raised(Fedex::RateError) # something like that
Thank you in advance.
Also RateError is raised here:
def process_request
api_response = self.class.post(api_url, :body => build_xml)
puts api_response if #debug == true
response = parse_response(api_response)
if success?(response)
options = response[:track_reply][:track_details]
if response[:track_reply][:duplicate_waybill].downcase == 'true'
shipments = []
[options].flatten.map do |details|
options = {:tracking_number => #package_id, :uuid => details[:tracking_number_unique_identifier]}
shipments << Request::TrackingInformation.new(#credentials, options).process_request
end
shipments.flatten
else
[options].flatten.map do |details|
Fedex::TrackingInformation.new(details)
end
end
else
error_message = if response[:track_reply]
response[:track_reply][:notifications][:message]
else
"#{api_response["Fault"]["detail"]["fault"]["reason"]}\n--#{api_response["Fault"]["detail"]["fault"]["details"]["ValidationFailureDetail"]["message"].join("\n--")}"
end rescue $1
raise RateError, error_message
end
end
added:
private
def fedex_track(tracking)
fedex.track(tracking_number: tracking)
end
And changed results on line 7 to:
results = fedex_track(order_tracking) rescue next

Gem Resque Error - Undefined "method perform" after Overriding it form the super class

First of all Thanks for you all for helping programmers like me with your valuable inputs in solving day to day issues.
This is my first question in stack overflow as I am experiencing this problems from almost one week.
WE are building a crawler which crawls the specific websites and extract the contents from it, we are using mechanize to acheive this , as it was taking loads of time we decided to run the crawling process as a background task using resque with redis gem , but while sending the process to background I am experiencing the error as the title saying,
my code in lib/parsers/home.rb
require 'resque'
require File.dirname(__FILE__)+"/../index"
class Home < Index
Resque.enqueue(Index , :page )
def self.perform(page)
super (page)
search_form = page.form_with :name=>"frmAgent"
resuts_page = search_form.submit
total_entries = resuts_page.parser.xpath('//*[#id="PagingTable"]/tr[2]/td[2]').text
if total_entries =~ /(\d+)\s*$/
total_entries = $1
else
total_entries = "unknown"
end
start_res_idx = 1
while true
puts "Found #{total_entries} entries"
detail_links = resuts_page.parser.xpath('//*[#id="MainTable"]/tr/td/a')
detail_links.each do |d_link|
if d_link.attribute("class")
next
else
data_page = #agent.get d_link.attribute("href")
fields = get_fields_from_page data_page
save_result_page page.uri.to_s, fields
#break
end
end
site_done
rescue Exception => e
puts "error: #{e}"
end
end
and the superclass in lib/index.rb is
require 'resque'
require 'mechanize'
require 'mechanize/form'
class Index
#queue = :Index_queue
def initialize(site)
#site = site
#agent = Mechanize.new
#agent.user_agent = Mechanize::AGENT_ALIASES['Windows Mozilla']
#agent.follow_meta_refresh = true
#rows_parsed = 0
#rows_total = 0
rescue Exception => e
log "Unable to login: #{e.message}"
end
def run
log "Parsing..."
url = "unknown"
if #site.url
url = #site.url
log "Opening #{url} as a data page"
#page = #agent.get(url)
#perform method should be override in subclasses
#data = self.perform(#page)
else
#some sites do not have "datapage" URL
#for example after login you're already on your very own datapage
#this is to be addressed in 'perform' method of subclass
#data = self.perform(nil)
end
rescue Exception=>e
puts "Failed to parse URL '#{url}', exception=>"+e.message
set_site_status("error "+e.message)
end
#overriding method
def self.perform(page)
end
def save_result_page(url, result_params)
result = Result.find_by_sql(["select * from results where site_id = ? AND ref_code = ?", #site.id, utf8(result_params[:ref_code])]).first
if result.nil?
result_params[:site_id] = #site.id
result_params[:time_crawled] = DateTime.now().strftime "%Y-%m-%d %H:%M:%S"
result_params[:link] = url
result = Result.create result_params
else
result.result_fields.each do |f|
f.delete
end
result.link = url
result.time_crawled = DateTime.now().strftime "%Y-%m-%d %H:%M:%S"
result.html = result_params[:html]
fields = []
result_params[:result_fields_attributes].each do |f|
fields.push ResultField.new(f)
end
result.result_fields = fields
result.save
end
#rows_parsed +=1
msg = "Saved #{#rows_parsed}"
msg +=" of #{#rows_total}" if #rows_total.to_i > 0
log msg
return result
end
end
What's Wrong with this code?
Thanks

Resources