Trying to import JSON string in to database using Rails - mysql

Exercise.rb - Model
def self.import!
#request = Net::HTTP.get(URI.parse('https://example.com/output'))
#exercises = JSON.parse(#request)
#exercises.each do |e|
existing = Exercise.exists?(e)
unless existing === false
tmp = existing.first
end
e[:sections_attributes] = e.delete("sections")
e[:questions_attributes] = e.delete("questions")
e[:answers_attributes] = e.delete("answers")
record = Exercise.create(e)
puts "Record #{record["id"]} updated / created"
end
end
I'm getting the following error when I run the import:
(0.9ms) COMMIT
TypeError: no implicit conversion of String into Integer
My gut feeling is because every item in there is a String. How do I go about converting the items or get the insert to ignore column types?
Excerpt of #request
> `[2] pry(Exercise)> e
=> {"publish_date"=>"2013-12-11",
"grade_id"=>2,
"exercise_type"=>3,
"week"=>1,
"content"=>"<hr />\r\n\r\nQuestions:\r\n\r\n",
"grammar_list"=>"",
"title_append"=>nil,
"sections"=>
[{"name"=>"Vocab",
"order"=>0,
"questions"=>
[{"question"=>"rgrthth",
"type"=>3,
"order"=>0,
"answers"=>[{"answer"=>"aa", "correct"=>true, "order"=>0}]},
{"question"=>"uh67jy7k",
"type"=>3,
"order"=>0,
"answers"=>[{"answer"=>"bb", "correct"=>true, "order"=>0}]},
{"question"=>"rgtdyjuyik",
"type"=>3,
"order"=>0,
"answers"=>[{"answer"=>"cc", "correct"=>true, "order"=>0}]}]}]}`
Output from updated code
2.1.0 :040 > Exercise.import!
(0.2ms) SELECT COUNT(*) FROM `exercises` WHERE `exercises`.`week` = 1 AND `exercises`.`exercise_type` = 3 AND `exercises`.`grade_id` = 2
From: /Users/pc-a/Sites/mailbox/app/models/exercise.rb # line 99 Exercise.import!:
92: def self.import!
93: #request = Net::HTTP.get(URI.parse('example.com/output'))
94: #exercises = JSON.parse(#request)
95:
96: #exercises.map(&:with_indifferent_access).each do |e|
97: next if Exercise.exists?(e[:week], e[:exercise_type], e[:grade_id])
98:
=> 99: binding.pry
100:
101:
102: e[:sections_attributes] = e.delete(:sections)
103: e[:sections_attributes].map! do |section_attributes|
104: section_attributes[:questions_attributes] = section_attributes.delete(:questions)
105: section_attributes[:questions_attributes].map! do |question_attributes|
106: question_attributes[:answers_attributes] = question_attributes.delete(:answers)
107: end
108: end
109:
110: binding.pry
111:
112: exercise = Exercise.new(e)
113: if exercise.save
114: puts "Exercise #{exercise.id} created!"
115: else
116: puts "Could not create Exercise: #{exercise.errors.full_messages.join('; ')}"
117: end
118: end
119: end
[1] pry(Exercise)> e
=> {"publish_date"=>"2013-12-11",
"grade_id"=>2,
"exercise_type"=>3,
"week"=>1,
"content"=>"<hr />\r\n\r\nQuestions:\r\n\r\n",
"grammar_list"=>"",
"title_append"=>nil,
"sections"=>
[{"name"=>"Vocab",
"order"=>0,
"questions"=>
[{"question"=>"rgrthth",
"type"=>3,
"order"=>0,
"answers"=>[{"answer"=>"aa", "correct"=>true, "order"=>0}]},
{"question"=>"uh67jy7k",
"type"=>3,
"order"=>0,
"answers"=>[{"answer"=>"bb", "correct"=>true, "order"=>0}]},
{"question"=>"rgtdyjuyik",
"type"=>3,
"order"=>0,
"answers"=>[{"answer"=>"cc", "correct"=>true, "order"=>0}]}]}]}
[2] pry(Exercise)> exit
From: /Users/pc-a/Sites/mailbox/app/models/exercise.rb # line 110 Exercise.import!:
92: def self.import!
93: #request = Net::HTTP.get(URI.parse('example.com/output'))
94: #exercises = JSON.parse(#request)
95:
96: #exercises.map(&:with_indifferent_access).each do |e|
97: next if Exercise.exists?(e[:week], e[:exercise_type], e[:grade_id])
98:
99: binding.pry
100:
101:
102: e[:sections_attributes] = e.delete(:sections)
103: e[:sections_attributes].map! do |section_attributes|
104: section_attributes[:questions_attributes] = section_attributes.delete(:questions)
105: section_attributes[:questions_attributes].map! do |question_attributes|
106: question_attributes[:answers_attributes] = question_attributes.delete(:answers)
107: end
108: end
109:
=> 110: binding.pry
111:
112: exercise = Exercise.new(e)
113: if exercise.save
114: puts "Exercise #{exercise.id} created!"
115: else
116: puts "Could not create Exercise: #{exercise.errors.full_messages.join('; ')}"
117: end
118: end
119: end
[1] pry(Exercise)> e
=> {"publish_date"=>"2013-12-11",
"grade_id"=>2,
"exercise_type"=>3,
"week"=>1,
"content"=>"<hr />\r\n\r\nQuestions:\r\n\r\n",
"grammar_list"=>"",
"title_append"=>nil,
"sections_attributes"=>
[[[{"answer"=>"aa", "correct"=>true, "order"=>0}],
[{"answer"=>"bb", "correct"=>true, "order"=>0}],
[{"answer"=>"cc", "correct"=>true, "order"=>0}]]]}

Try the following:
def self.import!
#request = Net::HTTP.get(URI.parse('https://example.com/output'))
#exercises = JSON.parse(#request)
#exercises.map(&:with_indifferent_access).each do |e|
next if Exercise.exists?(name: e[:name]) # or whatever the attribute(s) you use to determine the uniqueness of an Exercise
e[:sections_attributes] = e.delete(:sections)
e[:sections_attributes].map! do |section_attributes|
section_attributes[:questions_attributes] = section_attributes.delete(:questions)
section_attributes[:questions_attributes].map! do |question_attributes|
question_attributes[:answers_attributes] = question_attributes.delete(:answers)
end
end
exercise = Exercise.new(e)
if exercise.save
puts "Exercise #{exercise.id} created!"
else
puts "Could not create Exercise: #{exercise.errors.full_messages.join('; ')}"
end
end
end
end

Related

Error accessing data from an array in ruby ​on rails

The error tells me that the method '[]' is not defined in the line 127
this is my code and Idon't see the error
def verificar_area archivo
bandera= false
Spreadsheet.client_encoding = 'UTF-8'
book = Spreadsheet.open archivo
#wk = book.worksheet 0
areas = ["Secundaria",
"Preparatoria",
"Universitario",
"Edad 11 a 15 años",
"Edad de 16 a 19 años",
"Solo estudian",
"Adolescentes que trabajan y estudian"]
(1 .. #wk.row_count).each do |index_renglon|
#renglon_excel = #wk.rows[index_renglon]
area=#renglon_excel[8] #This is the line 127
if areas.include?(area)
bandera=true
else
bandera=false
break
end #fin if
end #fin for
return bandera
end
the error in the browser is this
You are getting the error because #renglon_excel is nil for that specific iteration
#renglon_excel[8]
And you are trying to access with index of [8] on nil
To avoid this you can add a check
#renglon_excel = #wk.rows[index_renglon]
next unless #renglon_excel
area = #renglon_excel[8]

Ruby: calling method within another method's conditional statement

I'm trying to call the method print_json within a conditional statement that is contained in another method named list_trends. I did this becauese my code was starting to look too nested. However I get an error when I run that says:
syntax error, unexpected tSTRING_BEG, expecting keyword_do or '{' or '('
...i_key]) ? print_trends : puts "Invalid API Key, operation ab...
Here is my code:
#!/usr/bin/ruby
require 'thor'
require 'json'
class ListTrends < Thor
desc "list trends", "list out trends from JSON file"
option :api_key, :aliases => "--api-key", :type => :string, :required => true
def print_json
json = File.read('trends_available.json')
trends_hash = JSON.parse(json)
trends_hash.each do |key|
key.each do |k,v|
puts "Trend #{k}: #{v}"
end
puts ""
end
end
def list_trends
re = /^(?=.*[a-zA-Z])(?=.*[0-9]).{8,}$/
if options[:api_key]
if re.match(options[:api_key]) ? print_json : puts "Invalid API Key, operation abort..."
end
end
end
ListTrends.start(ARGV)
This
if options[:api_key]
if re.match(options[:api_key]) ? print_json : puts "Invalid API Key, operation abort..."
end
Should just be
if options[:api_key]
re.match(options[:api_key]) ? print_json : puts "Invalid API Key, operation abort..."
end
Though I would prefer:
if options[:api_key]
if re.match(options[:api_key])
print_json
else
puts "Invalid API Key, operation abort..."
end
end
Or if you must put it on one line:
if options[:api_key]
if re.match(options[:api_key]) then print_json else puts "Invalid API Key, operation abort..." end
end

Ruby Sequel MySQL Insert Error

I am learning Ruby and I am using the Sequel gem to handle my model. but I keep running into an error I can't seem to hunt down. The thing that doesn't make sense is that is it failing on an insert because a field doesn't exist in a table that I am inserting into. However, I am not attempting to use the field that doesn't exist.
Here is my error:
0
{:id=>5, :name=>"barcelona"} : {:id=>4, :name=>"berlin"}
/Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/adapters/mysql.rb:175:in `query': Mysql::Error: Unknown column 'name' in 'field list' (Sequel::DatabaseError)
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/adapters/mysql.rb:175:in `block in _execute'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/database/logging.rb:33:in `log_yield'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/adapters/mysql.rb:175:in `_execute'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/adapters/shared/mysql_prepared_statements.rb:34:in `block in execute'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/database/connecting.rb:250:in `block in synchronize'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/connection_pool/threaded.rb:98:in `hold'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/database/connecting.rb:250:in `synchronize'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/adapters/shared/mysql_prepared_statements.rb:34:in `execute'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/adapters/mysql.rb:160:in `execute_insert'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/dataset/actions.rb:927:in `execute_insert'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/dataset/actions.rb:336:in `insert'
from travellingAmerican.rb:70:in `addDist'
from travellingAmerican.rb:64:in `block (2 levels) in addLocations'
from travellingAmerican.rb:61:in `each'
from travellingAmerican.rb:61:in `block in addLocations'
from travellingAmerican.rb:58:in `each'
from travellingAmerican.rb:58:in `addLocations'
from travellingAmerican.rb:93:in `<main>'
Here is models.rb:
#Database
require 'sequel'
def create
DB.create_table(:locations) do
primary_key :id
String :name, :unique=>true
end
DB.create_table(:distances) do
primary_key :id
foreign_key :to, :locations
foreign_key :from, :locations
Float :miles, :default=>-1
TrueClass :valid, :default=>0
unique [:to, :from]
end
end
def drop
begin
DB.drop_table(:distances)
rescue
puts "Couldn't drop Distances"
end
begin
DB.drop_table(:locations)
rescue
puts "Couldn't drop locations"
end
end
DB = Sequel.connect(:adapter=>'mysql', :host=>'myHost', :user=>'myUser', :password=>'myPass', :database=>'myDB')
if __FILE__ == $PROGRAM_NAME
puts "Will Execute"
drop
create
puts "Done Executing"
end
Now the file the error is actually in, travellingAmerican.rb:
#Traveling American
require './models.rb'
require 'json'
def urlCreator(cities)
urls = []
rootUrl = "https://maps.googleapis.com/maps/api/distancematrix/json?"
origin = "origins="
dest = "destinations="
key = "myApiKey"
cities.each do |city|
city = city.gsub(/[" "]/, '+')
newOrigin = origin + city + "|"
newDest = dest
cities.each do |inCity|
newDest += inCity + "|"
end
newUrl = rootUrl + newOrigin + "&" + newDest + "&" + key
urls.push(newUrl)
end
urls
end
def processFile(file)
cities = []
File.readlines(file).each do |line|
line = line.strip
if line.count(",") == 1
line = line.split()
else
cities.push(line)
end
end
return cities
end
def addLocations(cities)
cities.each do |city|
begin
DB[:locations].insert(:name => city.downcase)
rescue Sequel::UniqueConstraintViolation
puts "Duplicate, not added"
end
end
allLocs = DB[:locations].where(:name => cities).order(:name).all
#if you puts allLocs it works beautifully
for i in 0...allLocs.length
puts i
toLoc = allLocs[i]
for j in (i+1)...allLocs.length
fromLoc = allLocs[j]
puts toLoc.to_s + " : " + fromLoc.to_s
#If you comment out the line below everything runs fine, minus the insertion obviously
addDist(toLoc, fromLoc)
end
end
end
def addDist(tos, froms)
#the line with the error
DB[:distances].insert(:to=>tos, :from=>froms)
end
if __FILE__ == $PROGRAM_NAME
popSize = -1
file = ""
count = 0
ARGV.each do|arg|
if count == 0
popSize = arg.to_i
else
file = arg
end
count += 1
end
if popSize == -1 or file == ""
abort("Usage: ruby travellingAmerican.rb popSize cityList")
end
cities = processFile(file)
addLocations(cities)
puts urlCreator(cities)
end
Lastly here is cities.csv if you would like to run this on your own machine:
San Diego
Munich
Paris
Berlin
Barcelona
Monte Carlo
Cinque Terre
Turin
Milan
Florence
Rome
Venice
To run this on your own machine just execute ruby travellingAmerican.rb 1000 cities.csv in a shell.
I hope I have provided enough info for everyone! Thanks for looking.
There are some problems I detected:
Here you add the cities with downcase:
cities.each do |city|
begin
DB[:locations].insert(:name => city.downcase)
rescue Sequel::UniqueConstraintViolation
puts "Duplicate, not added"
end
end
The you read them in a Hash:
allLocs = DB[:locations].where(:name => cities).order(:name).all
The condition is without the downcase! So you get no result.
You could do:
allLocs = DB[:locations].where(:name => cities.map(&:downcase)).order(:name).all
Later you use
addDist(toLoc, fromLoc)
toLoc and fromLoc are both Hashes, but the should be the key for the table cities.
This should work:
addDist(toLoc[:id], fromLoc[:id])
As an alternative you can adapt the insertion in addDist
DB[:distances].insert(:to=>tos[:id], :from=>froms[:id])
The usage of for is not ruby-like. I would use directly Sequel::Dataset#each:
selection = DB[:locations].where(:name => cities.map(&:downcase)).order(:name)
selection.each{|toLoc|
selection.each{|fromLoc|
puts toLoc.to_s + " : " + fromLoc.to_s
#If you comment out the line below everything runs fine, minus the insertion obviously
addDist(toLoc[:id], fromLoc[:id])
}
}
(You could discuss, if the where and order methods are really needed here)

Lua - Error repeating a function?

I'm working on an 'impossible' game, where you are basically asked a bunch of trick questions.
The first time I run the script, everything works perfectly. If the user decides to play again by typing in 'y', it will re-run the mainScript function. However, the script automatically re-runs the mainScript after finishing it a second time, without taking user input. I might be making a simple mistake, I'm not sure. Here is the script: (Sorry, I know it is kind of long)
math.randomseed(os.time())
local lives = 3
local points = 0
Questions = {
{"What is the magic word?", "A) Please", "B) Abra-Cadabra", "C) Lotion", "D) Cheese", "c"},
{"Does anyone love you?", "A) Yes", "B) No", "C) Everyone loves me!", "D) My mother does", "b"},
{"How many fingers do you have?", "A) None", "B) Eight", "C) Seventeen", "D) Ten", "d"},
{"What is 1 + 1?", "A) Window", "B) Door", "C) Two", "D) That's a stupid question", "a"}
}
savedQuestions = {} --Load the Questions table into savedQuestions
for i, v in pairs(Questions) do
table.insert(savedQuestions, v)
end
function loadTable() --Load the savedQuestions into Questions
for i = 1, #savedQuestions do
table.insert(Questions, savedQuestions[i])
end
end
function waitForStart()
local chk = io.read() tostring(chk)
if (chk:sub(1, 5)):lower() == "start" then
return true
end
waitForStart()
end
function lookForAnswer(ans)
table.remove(Questions, number)
local input = io.read() tostring(input)
if input:lower() == ans then
points = points + 1
return true
end
lives = lives - 1
return false
end
function mainScript()
lives = 3
points = 0
print("Welcome to the Impossible quiz!")
print("Type 'start' when you are ready to begin\n")
waitForStart() io.write("\n")
for i = 1, #Questions do
number = math.random(1, #Questions)
local prob = Questions[number]
local q = prob[1]
local a = prob[6]
print(q)
print(prob[2] .. "\n" .. prob[3] .. "\n" .. prob[4] .. "\n" .. prob[5] .. "\n")
if lookForAnswer(a) then
print("Correct! Points: " .. points .. " Lives: " .. lives .. "\n\n")
else
print("WRONG! Points: " .. points .. " Lives: " .. lives .. "\n\n")
if lives <= 0 then
return false
end
end
end
return true
end
function checkForReplay()
print("Would you like to play again? (Y / N)")
local chk = io.read() tostring(chk)
if (chk:sub(1, 1)):lower() == "y" then
return true
end
return false
end
function checkWin()
if mainScript() then
print("You won!")
print("Points: " .. points .. "\n")
if checkForReplay() then
Questions = {}
loadTable()
mainScript()
else
exit()
end
else
print("You lose!")
print("Points: " .. points .. "\n")
if checkForReplay() then
Questions = {}
loadTable()
mainScript()
else
exit()
end
end
end
while true do
checkWin()
end
You should factor out the "startover" logic into the loop, you would see better. Then you notice how there is common code in both if chunks of your checkWin, factor that out too:
function checkWin()
if mainScript() then
print("You won!")
else
print("You lose!")
end
print("Points: " .. points .. "\n")
if not checkForReplay() then
exit()
end
end
while true do
checkWin()
-- if you get here you have not exited so start over:
Questions = {}
loadTable()
mainScript() -- oops! what's that doing here?
end
Note also that it is better to let the script return than call os.exit() (assuming that is what exit() is in your code -- see for example How to terminate Lua script?):
function checkWin()
if mainScript() then
print("You won!")
else
print("You lose!")
end
print("Points: " .. points .. "\n")
return checkForReplay()
end
local playAgain = checkWin()
while playAgain do
Questions = {}
loadTable()
playAgain = checkWin()
end

raise MysqlError; raise Mysql::Error both work, how did this happen?

Greetings,
I was working on mysql exceptions and I came across this interesting issue, in which a raised exception is responding to two different exception names. How did this happen?
-daniel
#!/usr/bin/env ruby
require 'rubygems'
require 'mysql'
require 'yaml'
require 'pp'
$config = YAML.load_file 'database.yml'
class ExceptionPrinter
def self.print msg, e
puts msg
pp e
end
end
# sample connect: dbh = Mysql.real_connect $config['database']['host'], $config['database']['user'], $config['database']['password'], $config['database']['db'], $config['database']['port']
# test 1 - what class is thrown?
begin
puts "Starting test - MysqlError"
dbh = Mysql.real_connect $config['database']['host'], $config['database']['user'], $config['database']['password'], $config['database']['db']
puts "Error: Code did not throw exception"
rescue MysqlError => e # MysqlError is not a valid exception catch
ExceptionPrinter.print "MysqlError", e
rescue Exception => e
ExceptionPrinter.print "Exception class", e
end
# test 2 - What class is thrown?
begin
puts "Starting test - Mysql::Error"
dbh = Mysql.real_connect $config['database']['host'], $config['database']['user'], $config['database']['password'], $config['database']['db']
puts "Error: Code did not throw exception"
rescue Mysql::Error => e
ExceptionPrinter.print "Mysql::Error", e
rescue Exception => e
ExceptionPrinter.print "Exception class", e
end
-- Output
Starting test - MysqlError
MysqlError
Starting test - Mysql::Error
Mysql::Error
It looks like one is just an alias to the other:
Mysql::Error
# => Mysql::Error
MysqlError
# => Mysql::Error
Based on that, I'm expecting that somewhere in the MySQL gem there's a line like this:
class Mysql
MysqlError = Mysql::Error
end
This implies MysqlError is a constant defined as the class Mysql::Error.