error: undefined method `delete' for nil:NilClass
"updated_at" => "",
"fias_ao_guid" => "\r\n",
"file_path" => nil
how delete "\r\n"?
splitted_records = []
id = 3141634
string = 0
row = 0
h = {}
record_candidate = {}
open('/home/dayanov-sa/PGadmin/finish.csv') do |csv|
csv.each_line do |line|
index = 0
row += 1
line.split(";").each do |key_filed|
record_candidate["#{key_filed.delete("\r\n")}"] = nil
end if row.eql?(1)
next if row.eql?(1)
copy_object = Marshal.load(Marshal.dump(line))
values = line.split(";")
record_candidate.keys.each do |keys|
index += 1
record_candidate[keys] = values[index].delete("\r\n")
end
id = id + 1
puts string
splitted_records << record_candidate
I'm trying to remove from the hash \ r \ n
This is because of some hash keys have nil values e.g. ("file_path" => nil)
You need to bypass the nil values
Your code will be like this:
record_candidate.keys.each do |keys|
index += 1
if !values[index].nil?
record_candidate[keys] = values[index].delete("\r\n")
end
end
Your code looks like an attempt to parse CSV with a header. Ruby already has that in stdlib:
require 'csv'
file_contents = File.read('/home/dayanov-sa/PGadmin/finish.csv')
data = CSV.parse(file_contents, headers: true, col_sep: ';')
splitted_records = data.map(&:to_h)
see ruby documentation on CSV
Related
I need some help/idea on how to dynamically position values in a 2D array.
Basically, I have a condition that must be met and that determines which column should the value be written.
This is what I have (a loop that pass conditions before writing the value):
#records.each do |client|
client_info = Report.get_client_info(client)
client_address = Report.get_client_address(client)
client_records = []
client_records << [client_info.id, client_info.full_name]
if #include_address == "1"
client_address.each_with_index do |address, i|
if client_records[i].present?
client_records[i][2] = address.full_address
client_records[i][3] = address.address_type
else
client_records << ["","", address.full_address, address.address_type]
end
end
end
if #include_contact == "1"
client_contact.each_with_index do |contact, i|
if client_records[i].present?
client_records[i][4] = contact.value
client_records[i][5] = contact.label
else
client_records << ["","","","", contact.value, contact.label]
end
end
end
end
Problem is: IF I want to make another condition, and the condition in between the two (conditions) is not true, the position of the column value set by: client_records[i][2] >> 2,3 etc... is hard coded, instead of the third condition occupying the place of the second condition's columns, it naturally leaves it blank and stays at the same place.
This is how it would look like:
Instead of:
How can I work around this?
For example, try that:
#records.each do |client|
client_info = Report.get_client_info(client)
client_address = Report.get_client_address(client)
client_records = []
line = [client_info.id, client_info.full_name]
[client_address.count, client_contact.count].max.times do |i|
if #include_address == "1" && client_address[i]
line << client_address[i].full_address << client_address[i].address_type
else
line << '' << ''
end
if ##include_contact == "1" && client_contact[i]
line << client_contact[i].value << client_contact[i].label
else
line << '' << ''
end
client_records << line.clone
line = ['', '']
end
end
I was handed a project from someone else, it's in Ruby On Rails, which I know VERY LITTLE. Basically, there is an EXPORT button, that the user clicks to send data to a CSV. I am tasked with sending this data to the view to be seen in HTML. (Thinking I could use dataTables). I have tried following examples, such as:
#example = StudentGroup.where(survey_id: #survey.id).order("groupNum")
and then using <%= #example %> in the view just to see the data and I get nothing. (Also extremely new to MySQL). I'll post the method, if ANYONE can help me, I'd very much appreciate it.
def download_results
if (user_signed_in?)
else
redirect_to new_user_session_path
end
#survey = Survey.find(params[:survey_to_view])
filename = #survey.name + " - " + Date.today.to_formatted_s(:short)
require "csv"
CSV.open(#survey.name+".csv", "wb") do |csv|
csv << [filename]
StudentGroup.where(survey_id: #survey.id).order("groupNum")
csv << []
csv << ["Summarized Results"]
csv << ["UCA","Group Number","Criteria 1","Criteria 2","Criteria 3","Criteria 4","Criteria 5","Criteria 6","Criteria 7","Criteria 8","Overall Team Contribution","Average(Would Work With Again)","Average(C1..C8)","Overall Team Contribution MINUS Average(C1..C9)"]
questions = #survey.questions
numQuestions = 0
questions.each do |q|
if(q.question_type != 2 && q.question_type != 4)
numQuestions = numQuestions+1
end
end
groups.each do |g|
answersCount = Answer.where(student_group_id: g.id).count
if(answersCount == numQuestions && answersCount != 0)
othersInGroup = StudentGroup.where(groupNum: g.groupNum, survey_id: #survey.id).order("groupNum")
size = othersInGroup.count-1
arr = []
criteria = SurveyQuestionDatum.where("number > 24 AND number < 35")
multiAvg = 0
teamCont = 0
criteria.each do |c|
avg = 0
othersInGroup.each do |o|
a = Answer.where(survey_question_datum_id: c.id, student_group_id: o.id).first
if(o.uca != g.uca)
if(a.nil?)
size = size-1
else
avg = avg + a.answer[g.uca].to_i
end
end
end
avg = avg.to_f/size
if(c.number == 33)
teamCont = avg
end
if(c.number < 33)
multiAvg = multiAvg+avg
end
arr << avg
end
multiAvg = multiAvg.to_f/8
arr << multiAvg
arr << teamCont-multiAvg
arr.insert(0,g.uca, g.groupNum)
csv << arr
end
end
csv << []
csv << []
csv << ["Raw Student Answers"]
groups = StudentGroup.where(survey_id: #survey.id).order("groupNum")
size = groups.count
csv << ["UCA", "F-Number", "Group Number"]
groups.each do |g|
answersCount = Answer.where(student_group_id: g.id).count
if(answersCount == numQuestions && answersCount != 0)
othersInGroup = StudentGroup.where(groupNum: g.groupNum, survey_id: #survey.id).order("groupNum")
csv << []
csv << [g.uca, g.FNum, g.groupNum]
answers = Answer.where(student_group_id: g.id)
csv << ["Question Number", "Question", "Answer"]
answers.each do |a|
datum = a.survey_question_datum
question = datum.question
#question_types = {"0" => "short", "1" => "paragraph",
#2" => "title", "3" => "fivept", "4" => "fixed",
#5" =>"ranking", "6"=>"tenpoints","7"=>"hundredpoints"}
ansText = ""
if(question.question_type == 0)
ansText = a.answer
elsif (question.question_type == 1)
if(question.rule == 'perMember')
othersInGroup.each do |o|
ansText = ansText+"#{o.uca},#{a.answer[o.uca]},"
end
elsif(question.rule == 'default')
ansText = a.answer
end
else (question.question_type == 3)
othersInGroup.each do |o|
ansText = ansText+"#{o.uca},#{a.answer[o.uca]},"
end
end
ansText = ansText.chomp(',')
ansText = ansText.split(',')
ansText.insert(0,datum.number,question.question_text)
csv << ansText
end
end
end
end
send_file(#survey.name+".csv", :filename => filename+".csv")
end
You need a new controller action. Take a look at http://guides.rubyonrails.org/layouts_and_rendering.html
Create an index (or show, or whatever you want to call it, maybe example) action. Make sure it is in your routes.
http://guides.rubyonrails.org/getting_started.html#adding-a-route-for-comments
do not use the download_results code.
set your #example variable the way you were trying to do.
create a view for your index action
add the data to your index view.
If you put code in your download_results method (action) it will never get rendered because of the send_file method call.
Did you create a brand new controller / action / view? Did you use generators? Have you really practiced doing this setup exactly the way the examples, videos, tutorials say to do it? If you have, you have seen how all the pieces (models, controllers, actions, views) come together. You should have seen how render statements come into play. Do that, exactly as the tutorials say to do it and you will get the idea.
If you want to use the same content that the download action uses, refactor the code to extract a method that is used both actions.
This is related to respond_to part, check the docs.
send_file(#survey.name+".csv", :filename => filename+".csv")
Your code above simply means you click the button, the controller will respond you with a csv file. So, if you want a html, the controller should be able to respond to html as well.
In Rails console
> h_json = {key: "value"}.to_json;
#=> "{\"key\":\"value\"}"
> s_json = %Q|{"key": "value"}|
#=> "{\"key\": \"value\"}"
> s_json.class
#=> String
> h_json.class
#=> String
We can see both h_json and s_json have the same String class, and looks the same, however
#=> "{\"key\": \"value\"}"
> s_json == h_json
#=> false
They don't equals each other, I don't understand why.
there is a space in the s_json, if you checked the source code of the to_json function
# File activesupport/lib/active_support/json/encoders/hash.rb, line 33
def to_json(options = nil) #:nodoc:
hash = as_json(options)
result = '{'
result << hash.map do |key, value|
"#{ActiveSupport::JSON.encode(key.to_s)}:#{ActiveSupport::JSON.encode(value, options)}"
end * ','
result << '}'
end
this function doesn't add a space between the colon : and the value.
So actually,
h_json = "{\"key\":\"value\"}"
and
s_json = "{\"key\": \"value\"}"
if you set s_json = "{\"key\":\"value\"}" they must be equal.
input = {"color"=>["red"],"size"=>["s","l"]}
json_obj = [{"color":"red","id":"123","size":"s","name":"test"},
{"color":"yellow","id":"124","size":"s","name":"test"},
{"color":"red","id":"125","size":"l","name":"test"}]
Output should be
output["red_s"] = {"color":"red","id":"123","size":"s","name":"test"}
output["red_l"] = {"color":"red","id":"125","size":"l","name":"test"}
output is the combinations of the input and a find on the json_obj.
How to get the output in rails?
I have the below script to get the combinations ie.red_s and red_l,
ary = input.map {|k,v| [k].product v}
output = ary.shift.product(*ary).map {|a| Hash[a]}
And
output[red_s]=json_obj.find{|h| h["color"] == "red" and h["size"] == "S"}
I don't want to have any hardcodings in code like color and size as above.
I think this should get you close to what you want.
Note the "ticks" around your json array object (what you had is not valid ruby)
The other issue is you would have to figure a better way to create the output hash key.
require 'json'
input = {"color"=>["red"],"size"=>["s","l"]}
output = {}
json_obj = '[{"color":"red","id":"123","size":"s","name":"test"},
{"color":"yellow","id":"124","size":"s","name":"test"},
{"color":"red","id":"125","size":"l","name":"test"}]'
found = JSON.parse json_obj
input.each_key do |key|
found = found.select { |item| input[key].include?(item[key]) }
end
puts found
found.each do |item|
output_key = ""
input.each_key do |key|
output_key = "#{item[key]}_" + output_key
end
output["#{output_key}"] = item.to_json
end
puts output
What I want to do is something like this:
searchid = 4
while searchid != -1
#a += A.find(searchid)
#b = B.find(searchid)
searchid = #b.parentid
end
The problem being the line
#a += A.find(searchid)
The error being something like
NoMethodError: undefined method `+' for #<A:0x173f9a0>
So, how do you combine multiple 'find' requests?
You have to initialize #a = [] as an array before the += .
searchid = 4
#a = []
while searchid != -1
#a += A.find(searchid)
#b = B.find(searchid)
searchid = #b.parentid
end
You can combine them like:
searchid = 4
#a = []
while searchid != -1
#a += A.find(searchid)
#a += B.find(searchid)
searchid = #a.last.parentid
end
Got it to work (with help).
Did the following:
#a = []
with
#a << A.find_by_something(something)
seems to have worked.
Also using #a.compact! to get rid of the null entries.
Thanks for all the help :)