First off, I apologize in advance for any incorrect terms or general misunderstanding of ruby/rails/html that I may display in this question, as I'm still learning the languages and how they work. I've been given a gui to work on and fix bugs for and after upgrading from rails 3.0 to 3.2 I'm seeing artifacts in many places.
Specifically what I'm asking in this post though is a string display issue. The short version of what I have is a message thread displayed with in a web page that looks close to what you'd see in most text message clients on smartphones now days. The page displays a persons name if the system knows who they are (registered with us) and just a mobile number if they are not.
However the issue is that instead of displaying 5554440002, it's displaying as:
["(", "5", "5", "5", ")", " ", "4", "4", "4", "-", "0", "0", "0", "1"]
Looking around the net, and on stack overflow I found this post To be the closest thing to answering my issue. However the suggestion of dropping the = out of <%= ends in the mobile number no longer displaying.
The line of code that generates this output is:
<%= find_associated_account conversation_message['from'] -%>
Edit 1 (definition):
def find_associated_account(input)
if input[0..0] == $operator.domestic_code.to_s
input = input[1..10]
end
if #account.associated_accounts and #account.associated_accounts.count > 0
if !(input.match(/#/)) && !(input.match(/MISSING_MAILBOX/))
input = input[0..9]
end
begin
acc = #account.associated_accounts.find_by_number(input)
if acc
return get_display_name_for_account(acc)
end
end
return format_mdn(input)
end
def format_mdn(input)
domestic_length = $operator.domestic_mask.count('#')
number_cc_stripped = input.sub(/\A[#{$operator.domestic_code}]/, '')
if /^[0-9]{#{domestic_length}}$/.match(number_cc_stripped)
result = []
count = 0
$operator.domestic_mask.each_char do |c|
if c == '#'
result << number_cc_stripped[count,1]
count += 1
else
result << c
end
end
return result.to_s
end
return input
end
Any advice given will be greatly appreciated and any other information needed will be provided.
Fixed this after messing with the return value of format_mdn. I changed the initialization of result to "" instead of [] which I'm guessing changed the type of the variable? In any case the final code for this definition is:
def format_mdn(input)
domestic_length = $operator.domestic_mask.count('#')
number_cc_stripped = input.sub(/\A[#{$operator.domestic_code}]/, '')
if /^[0-9]{#{domestic_length}}$/.match(number_cc_stripped)
result = []
count = 0
$operator.domestic_mask.each_char do |c|
if c == '#'
result << number_cc_stripped[count,1]
count += 1
else
result << c
end
end
return result.join("")
end
result = number_cc_stripped
return result
end
Related
I have a spreadsheet of members designed as below:
My aim is to upload some columns and exclude others. In this case, I wish to upload only the name, age and email and exclude the others. I have been able to achieve this using the slice method as shown below:
def load_imported_members
spreadsheet = open_spreadsheet
spreadsheet.default_sheet = 'Worksheet'
header = spreadsheet.row(1)
(2..spreadsheet.last_row).map do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
member = Member.find_by_id(row["id"]) || Member.new
member.attributes = row.to_hash.slice("id", "name", "age", "email")
member
end
end
The problem is that last_row considers all the rows upto the last one (13), and since there are validations on the form, there are errors due to missing data as a result of the empty rows (which shouldn’t be considered). Is there a way I can upload only specific columns as I have done, yet limit to only the rows that have data?
You might want to chain the map call off of a reject filter like this example
You may just need to change the map line to this (assuming the missing rows all look like those above):
(2..spreadsheet.last_row).reject{|i| spreadsheet.row(i)[0] }.map do |i|
This is assuming the blank rows return as nil and that blank rows will always have all four desired fields blank as shown in the image. The reject call tests to see if spreadsheet.row(i)[0], the id column, is nil, if so the item is rejected from the list output given to map
Thanks for this question. I have learned some things from this question.
I have shortlisted your answer [note: use 'ROO' gem]
def load_imported_members(member)
spreadsheet = open_spreadsheet(member)
spreadsheet.each do |records|
record = #spreadsheet ? Hash[[#header, #spreadsheet.row(records)].transpose] : Hash[records] # transpose for xlsx records and
attributes = {id: record['id'], name: record['name'], email: record['email'], age: record['age']}
member_object = Member.new(attributes)
if member_object.valid?
if Member.find(attributes[:id])
Member.find(attributes[:id]).update(attributes)
else
member_object.save
end
end
end
end
You can parse your uploaded file using Roo gem.
def self.open_spreadsheet(member)
case File.extname(member.file.original_filename)
when ".csv" then
Roo::CSV.new(member.file.expiring_url, csv_options: {headers: true, skip_blanks: true, header_converters: ->(header) { header.strip }, converters: ->(data) { data ? data.strip : nil }})
when ".xlsx", ".xls" then
#spreadsheet = Roo::Spreadsheet.open(member.file.expiring_url)
#header = #spreadsheet.row(1)
(2..#spreadsheet.last_row)
end
end
Here I have used s3 uploaded url i.e expiring_url. Hope This will helpful. I have not tested. sorry, for small errors.
If you have used validations for name, email, and age. This will surely help u..
I am trying to figure out how can i distribute particular elements of a list, based on an if statement.
This is the list:
#x = ["american", "assistive", "audio", "blind", "braille", "closed-captioning", "closed-captioning", "deaf", "low", "phone", "question-circle", "question-circle", "sign", "tty", "universal", "wheelchair"]
This is my haml code:
%ul.list-inline
- #x.each do |i|
- if i[0].length < i[1].length
%li
%i{:class=>"fas fa-#{i[0]} fa-2x"}
%span.f6 #{i[0]}
- else
%li
%i{:class=>"far fa-#{i[1]} fa-2x"}
%span.f6 #{i[1]}
What i am trying to do, is to determine the length of each string in the list and compare it to the length of the next string in the list.
Once the second string is determined as being a duplicate, it should go under the else statement.
The problem i am facing, is that by going with i[0], instead of the first string in the list, i am getting the first letter of the each string in the list.
I don't know if my way of using length is the best way to solve this issue, so if anyone else has a better solution i am open for it, as long as it gets the job done.
I am thinking that maybe if i could filter the elements in the list based on which elements are unique and which are duplicates, i could then distribute them accordingly.
But how i do that?
Thank you.
To answer the first part of your question where i[0] or i[1] is returning a single letter instead of the element, let us examine your code:
#x.each do |i|
Here i is the element. So in the first iteration, i is 'american'. So when you call i[0] it returns the first character of the string which is a and i[1] returns m and both their lengths are 1.
Instead, you should modify your code like this:
%ul.list-inline
- #x.each_cons(2) do |current, next|
- if current.length < next.length
%li
%i{:class=>"fas fa-#{current} fa-2x"}
%span.f6 #{current}
- else
%li
%i{:class=>"far fa-#{next} fa-2x"}
%span.f6 #{next}
Regarding the second part of your question, you have defined #x as:
#x = ["american", "assistive", "audio", "blind", "braille", "closed-captioning", "closed-captioning", "deaf", "low", "phone", "question-circle", "question-circle", "sign", "tty", "universal", "wheelchair"]
To fetch unique elements:
#x_uniq = #x.uniq
To fetch duplicates:
#x_dup = #x.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }.select{ |k,v| v > 1 }.keys
which returns
["closed-captioning", "question-circle"]
In my opinion, using the second way to filter the data and using it is a better solution than comparing elements with their lengths.
Hope this helped.
Use Enumerable#each_cons:
- #x.each_cons(2) do |cur, nxt|
- if cur.length < nxt.to_s.length
...
- else
...
I'm pretty sure I got it wrong. But I want this program to run through the "phone_numbers.txt" and replace anything that is repetitive except ["Employee Marked Urgency as: low", "Employee Marked Urgency as: high"] The result of this code is absolutely nothing. Nothing changed. Any tips?
file_names = ['phone_numbers.txt']
file_names.each do |file_name|
words_to_exclude = ["Employee Marked Urgency as: low", "Employee Marked Urgency as: high"]
text = File.read(file_name)
lines = text.split("\n")
new_contents = lines.uniq.reject do |word|
words_to_exclude.include? word
end.join("\n")
File.open(file_name, "w") { |file| file.puts new_contents }
end
I am not sure I understood it properly, but using Array#uniq with a block should do the trick:
require 'digest/sha1' # to generate uniqs
file_names = ['phone_numbers.txt']
words_to_exclude = ["Employee Marked Urgency as: low",
"Employee Marked Urgency as: high"]
file_names.each do |file_name|
res = File.readlines(file_name).each_with_index.uniq do |s, idx|
words_to_exclude.include?(s) ?
Digest::SHA1.hexdigest(idx.to_s) : s
end.join("\n")
File.write(file_name, res)
end
What’s going on here: if we encountered the word from our list, we generate a uniq enough string to let is pass anyway; otherwise we use the original string to compare.
I'd like to do something like this:
["START", "a", "b", "c", "STOP", "START", "d", "e", "STOP"].each do |message|
if message == "START"
Transaction.begin
elsif message == "STOP"
Transaction.commit if Transaction.active?
else
begin
Message.create!(body: message)
rescue
Transaction.rollback
end
end
end
In short, I have a stream of 'messages' and I'd like to transactionalise parts of that stream.
Whenever a "START" appears on the stream, a new transaction is begun. Whenever a "STOP" appears, the transaction is committed.
I'm struggling with the transactions.
I can see that I can do ActiveRecord::Base.transaction do ... end, but that won't work in this case unless I batch everything up, which isn't possible here because of the streams.
I saw that there's a transaction manager buried in ActiveRecord that I could potentially use (https://github.com/rails/rails/blob/0d76ab9c6f01e6390ba8878a296ff9d3ac6b9aa8/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb) but I haven't been able to get my tests passing against it.
I think part of the problem is also RSpec's transactional fixtures interfering, although disabling these didn't seem to solve the problem either.
Any help would be appreciated.
Thanks
you can manage transaction the following way
manager = ActiveRecord::Base.connection.transaction_manager
...
manager.begin_transaction
...
manager.commit_transaction
...
manager.rollback_transaction
or in your case
manager = ActiveRecord::Base.connection.transaction_manager
["START", "a", "b", "c", "STOP", "START", "d", "e", "STOP"].each do |message|
if message == "START"
manager.begin_transaction
elsif message == "STOP"
manager.commit_transaction
else
begin
Message.create!(body: message)
rescue
manager.rollback_transaction
end
end
end
I'd do this:
messages.chunk {|value| value != 'START' && value != 'STOP'}.each do |is_data, bodies|
if is_data
Message.transaction do
bodies.each {|body| Message.create(body: body)}
end
end
end
The first step is to use chunk to group the messages. The output of this is an array of pairs. If the first value of the pair is true, then the second value is the array of bodies, if not the bodies are just true false. With the data thus reorganised it is then trivial to use the existing transaction method.
I am starting out, so this code may not be as efficient as it could be, but I try. This is a text based game, something happens and the player must decide if he wants to continue or not.
but Everyone is different. so everyone is going to answer with some variation of "yes". How can I get the program to move on if someone types any variation of "yes" the commas give me a syntax error, and i don't know how else to get it to separate the possible answers.
def continueyn():
option1_des1 = raw_input("> ")
if option1_des1 == "yes", "Yes", "forward", "Forward", "Full impulse", "Full Impulse", "yeah", "yup", "Yup", "Yeah":
gravityp1()
elif option1_des1 == "no":
bearing(), userinput()
else:
print "Sorry Captain, I didn't get that. What did you say?"
continueyn()
Using 'or', as pointed out in the comments is incorrect. The correct way to go ahead through this would be either using lists and a loop, or iterating using "in":
Method 1:
option1_des1 = raw_input("> ")
if option1_des1 in {"yes", "Yes", "forward"} :
print "yes"
elif option1_des1 == "no":
print "no"
else:
print "Sorry Captain, I didn't get that. What did you say?"
Method 2:
You can also make a list and then go across values of the list like this-
flag=True
yesList = ['yes', 'Yes', 'forward']
option1_des1 = raw_input("> ")
for element in yesList:
if option1_des1 == element:
print "yes"
flag=False
break;
if option1_des1 == "no" and flag:
print "no"
elif flag:
print "Sorry Captain, I didn't get that. What did you say?"
Even better, you can use regex to match several variations of one type instead of figuring out every permutation. The xample below only covers "yes", but you can make a list of words like in method 2.
import re
pattern = 'yes'
option1_des1 = raw_input("> ")
matchObj = re.search(pattern, option1_des1, re.I)
if matchObj:
print "yes"
elif option1_des1 == "no":
print "no"
else:
print "Sorry Captain, I didn't get that. What did you say?"
Similar to sbhatla's answer you could use a list and use the built in "in" function which returns as a boolean.
yesoptions = ["yes", "Y", "etc"]
if option_des1 in yesoptions:
#runs actions for a yes answer
elif option in:
etcetc
else:
etc..