I'm following this tutorial CSV-FILE-EXPORT-IMPORT-RAILS but something im doing wrong, because i got an silly error when i'm trying to create my object uninitialized constant CuentaContablesController::False. I can read the file without problem, but this error is giving me an headache! Any help will be appreciated!
The method for import in my controller(cuenta_contable_controller.rb) looks like this;
class CuentaContablesController < ApplicationController
....
def upload(params)
logger.info "**File loaded***"
infile = params[:file].read
n, errs = 0, []
#archivo = []
SV.parse(infile) do |row|
n += 1
# SKIP: header i.e. first row OR blank row
next if n == 1 or row.join.blank?
cuenta_contable = CuentaContable.build_from_csv(row)
if cuenta_contable.valid?
cuenta_contable.save
#archivo << row
else
errs << row
end
end
logger.info errs
flash[:success] = "Las cuentas contables fueron cargadas."
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #archivo }
end
end
And my model(cuenta_contable.rb) like this
class CuentaContable < ActiveRecord::Base
....
def self.build_from_csv(row)
ultimo_nivel = (row[5].downcase=="si") ? (True):(False)
#cuenta = find_or_initialize_by_cuenta("#{row[0]}-#{row[1]}-#{row[2]}")
# Buscas el archivo existing customer from email or create new
cuenta = CuentaContable.new(:cuenta => "#{row[0]}-#{row[1]}-#{row[2]}",
:descripcion => "#{row[3].titleize}",
:categoria_cuenta => "#{row[4].titleize}",
:ultimo_nivel=> ultimo_nivel)
return cuenta
end
You're using True instead of true (likewise for false).
But neither are necessary; the ternary is superfluous and over-parenthesized:
# Ick!
ultimo_nivel = (row[5].downcase=="si") ? (True):(False)
# Pretty!
ultimo_nivel = row[5].downcase == "si"
You might even use a helper to turn row 5 into a boolean and remove it from the mainline code.
Related
I am very new to ruby and rails. I am trying to output all the parsed whois info to json output. I have the following:
class WhoisController < ApplicationController
def index
c = Whois::Client.new
record = c.lookup("google.com")
parser = record.parser
created = parser.created_on
msg = {:created => created}
render :json => msg
end
end
Output:
{"created":"1997-09-15T00:00:00.000-07:00"}
However, the parser has a LOT more info available....without knowing all the fields available, how do I dump all the keys/values to json?
I've tried:
class WhoisController < ApplicationController
def index
c = Whois::Client.new
record = c.lookup("google.com")
parser = record.parser
msg = {:whois => parser}
render :json => msg
end
end
But end up getting:
SystemStackError in WhoisController#index
EDIT:
I've also tried:
parser.attributes.each do |attr_name, attr_value|
puts attr_name
end
But end up getting another error:
undefined method `attributes' for #<Whois::Parser:0x00007fc030d74018>
Both Python and Go (through reflection) can do this. What is the Ruby way to achieve this?
EDIT:
class WhoisController < ApplicationController
def index
c = Whois::Client.new
record = c.lookup("google.com")
parser = record.parser
msg = {}
for x_prop in Whois::Parser::PROPERTIES
msg[x_prop] = parser.send(x_prop)
end
render :json => msg
end
end
This works ONLY if all the properties exist on parser. However, some domain names don't have all the properties and will result in:
Unable to find a parser for property `registrant_contacts'
I then try to set it only if that property exists:
msg = {}
for x_prop in Whois::Parser::PROPERTIES
parser.has_attribute?(:x_prop)
msg[x_prop] = parser.send(x_prop)
end
render :json => msg
I get another error:
undefined method `has_attribute?'
EDIT #3:
I've also tried:
msg = {}
for prop in Whois::Parser::PROPERTIES
msg[prop] = parser.send(prop) if parser.respond_to?(prop)
end
render :json => msg
This still fails if the property is missing in parser. ;(
class WhoisController < ApplicationController
def index
c = Whois::Client.new
record = c.lookup("google.com")
parser = record.parser
msg = {}
for x_prop in Whois::Parser::PROPERTIES
msg[x_prop] = parser.send(x_prop)
end
render :json => msg
end
end
in few cases something properties can be empty and cause an error, to escape this:
begin
msg[x_prop] = parser.send(x_prop)
rescue
# do nothing
end
For SystemStackError in WhoisController#index:
I think it is because you are calling whois with Whois again at record = Whois.whois("google.com"). Try record = whois("google.com").
For undefined method `attributes' for #<Whois::Parser:0x00007fc030d74018>:
attributes method does not exit for the whois parser.
See https://whoisrb.org/docs/v3/parser-properties/ .
You can use methods or inspect.
c = Whois::Client.new
record = c.lookup("google.com")
parser = record.parser
render json: parser.methods.to_json
render json: parser.inspect.to_json
Hi in the following code although the where query inside create method i.e. variable #count_of_fav_texts_present fetches 1 record in the rails console, but in controller the value of #count_of_fav_texts_present is zero and going inside the first if clause.
Also in the internal if clause the query for find_by i.e variable var_fav_text is giving NilClass. Although when I check it in console the value is not Nil, and it has one record.
I am very new to Rails and I am not sure what mistake I am making. Please help.
class NewfavoriteTextsController < ApplicationController
before_action :set_text
before_action :set_favgroup
before_action :authenticate_user!
def create
#count_of_fav_texts_present = Favorite.where(favorited_id: #text_id, user_id: current_user.id).count
if #count_of_fav_texts_present == 0
if Favorite.create(favorited: #text, user: current_user)
if Newfavorite.create(favorite_group_id: #fav_group, newfavorited: #text)
var_fav_text = Favorite.find_by(favorited_id: #text_id, user_id: current_user.id)
cnt_of_var = var_fav_text.counter
var_fav_text.counter = cnt_of_var + 1
var_fav_text.save
else
# do something
end
else
# do something
end
else
# for condition when var is greater than 0
if Newfavorite.create(favorite_group_id: #fav_group, newfavorited: #text)
var_fav_text = Favorite.find_by(favorited_id: #text_id, user_id: current_user.id)
cnt_of_var = var_fav_text.counter
var_fav_text.counter = cnt_of_var + 1
var_fav_text.save
else
# do something
end
end
end
def destroy
# do something
end
private
def set_text
#text = Text.find(params[:text_id] || params[:id])
end
def set_favgroup
#fav_group = params[:fav_group_id]
end
end
Thanks in advance.
I have two methods in two different controllers (Posts & Boards). They are almost same. The difference is only model-instance-association name. To DRY this I think to write the method in module, but how to share it between Post and Board?
def init_post_comments
#user = current_user
a = #user.posts.pluck(:id) # not very nice...
b=params[:post_ids] ||= []
b = b.map(&:to_i)
follow = b - a
unfollow = a - b
follow.each do |id| # checkbox just checked
#post = Post.find_by_id(id)
if #post.users.empty?
#post.update_attribute(:new_follow, true)
end
#user.posts << #post
end
unfollow.each do |id| # if checkbox was unchecked
#post = Post.find_by_id(id)
remove_post_from_user(#post)# here we destroy association
end
if follow.size > 0
get_post_comments_data
end
redirect_to :back
end
UPDATE Ok, if I'll move the methods to model's concern how I should work with associations here? Here #user.posts.pluck(:id) and here #user.boards.pluck(:id) with what I can replace posts and boards so it can work with both of them?
So, I did it! I don't know if it's right way, but I DRY this code.
Two controllers:
posts_controller.rb
def init_comments
if Post.comments_manipulator(current_user, params[:post_ids] ||= []) > 0
#posts = Post.new_post_to_follow
code = []
#posts.each do |post|
group = post.group
code = code_constructor('API.call')
end
Post.comments_init(get_request(code), #posts)
end
redirect_to :back
end
boards_controller.rb
def init_comments
if Board.comments_manipulator(current_user, params[:board_ids] ||= []) > 0
#boards = Board.new_board_to_follow
code = []
#boards.each do |board|# подготовка запроса
group = board.group
code = code_constructor('API.call')
end
Board.comments_init(get_request(code), #boards)
end
redirect_to :back
end
As you can see they are absolutely same.
In models board.rb and post.rb - include CommentsInitializer
And in models\concerns
module CommentsInitializer
extend ActiveSupport::Concern
module ClassMethods
def comments_manipulator(user, ids)
relationship = self.name.downcase + 's'
a = user.send(relationship).pluck(:id)
b = ids.map(&:to_i)
follow = b - a
unfollow = a - b
follow.each do |id| # start to follow newly checked obj
#obj = self.find_by_id(id)
if #obj.users.empty?
#obj.update_attribute(:new_follow, true)
end
user.send(relationship) << #obj
end
unfollow.each do |id| # remove from following
#obj = self.find_by_id(id)
remove_assoc_from_user(#obj, user)#destroy relation with current user
end
follow.size
end
def comments_init(comments, objs)
i = 0
objs.each do |obj| # updating comments data
if comments[i]['count'] == 0
obj.update(new_follow: false)
else
obj.update(new_follow: false, last_comment_id: comments[i]['items'][0]['id'])
end
i += 1
end
end
def remove_assoc_from_user(obj, user)
user = user.id
if user
obj.users.delete(user)
end
end
end
My code works. If you know how to make it better please answer!
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....
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