I have been getting this error, no implicit conversion of Symbol into Integer. I searched for this error but don't really understand it. Code is at the bottom. Once it gets to this "if q[:text_field].is? Array" that is when it gives the error and I'm sure that the rest of that code is wrong. But no idea how to fix it.
pages = Vovici::API.new(#pid).survey_structure
This is a sample of the api data that I'm calling with the code above.
[{:q_fill_in=>
{:heading=>{:text=>"1"},
:instructions=>{:text=>nil},
:body=>{:text=>"Pac"},
:list_caption=>{:text=>{:#type=>"plain"}},
:total_label=>{:text=>"Total"},
:text_field=>
[{:label=>{:text=>"first"},
:preselection=>{:text=>{:#type=>"plain"}},
:symbol=>{:text=>{:#type=>"plain"}},
:#id=>"1",
:#dbheading=>"Q1_1",
:#row=>"0",
:#size=>"20",
:#xmltype=>"text",
:#required=>"false",
:#compare_expression=>"-1",
:#topic_first=>"true",
:#slider=>"false",
:#sliderstep=>"1",
:#published=>"true",
:#usecalendarpopup=>"true",
:#insert_symbol_left=>"false",
:#label_width=>"3",
:#text_area_width=>"9"},
{:label=>{:text=>"id"},
:preselection=>{:text=>{:#type=>"plain"}},
:symbol=>{:text=>{:#type=>"plain"}},
:#id=>"2",
:#dbheading=>"Q1_2",
:#row=>"0",
:#size=>"20",
:#xmltype=>"text",
:#required=>"false",
:#compare_expression=>"-1",
:#topic_first=>"true",
:#slider=>"false",
:#sliderstep=>"1",
:#published=>"true",
:#usecalendarpopup=>"true",
:#insert_symbol_left=>"false",
:#label_width=>"3",
:#text_area_width=>"9"}],
:#dbheading=>"Q1"}
This is code from my rb file
def process
pages = Vovici::API.new(#pid).survey_structure
pages.each do |page|
if page[:q_fill_in]
process_fill_in(*page[:q_fill_in])
end
end
end
def process_fill_in(*questions)
questions.each do |q|
if q[:text_field].is? Array
sub_qs = q[:text_field]
else
sub_qs = [q[:text_field]]
end
q_text = clean_question_text(q[:body][:text])
sub_qs.each do |sq|
sub_text = clean_question_text(sq[:label][:text])
q_name = [q_text, sub_text.reject { |i| i.nil? || i.empty? }.join("--")]
#survey.questions.create!(qheader: sq[:#dbheading], qtext: q_name)
end
end
end
def clean_question_text(text)
match = /( )?(<.*?>)?(.+)( )?(<\/.*>)?/.match(text)
match[3]
end
Can anyone please help?
This error means that you've used [] on an array but you've passed something that doesn't make sense to an array. In this particular case it's telling you that q which you are trying to use as a hash is in fact an array.
This is happening because process_fill_in(*page[:q_fill_in]) is turning the hash into an array of key-value pairs (because of the *). I'm not sure why you've got a splat there at all.
Related
I'm trying to convert some values in a hash into a string but the type stays the same.
recommended_stores = []
results['data'].each do |stores_list|
stores_list['stores'].each do |store|
store['id'].to_s
end
recommended_stores << stores_list['stores']
end
Am I missing something here?
the method #to_s just returns the element converted to a string, but does not actually convert the element to a string permanently. instead of using #each, you could use #map, like this.
results['data'].map do |stores_list|
stores_list['stores'].each do |store|
store['id'] = store['id'].to_s
end
end
That would return an array of arrays, if you want it to be just one array you can use #flat_map.
you got everything but you are not storing it, i think assigning the value of hash with the value.to_s would work, can you try as below
recommended_store = []
results['data'].each do |stores_list|
stores_list['stores'].each do |store|
store['id'] = store['id'].to_s
end
recommended_store << stores_list['stores']
end
Note : in your question array declared is "recommended_store" and last line you are pushing elements in to "recommended_stores" hope its just a typo, and not the cause of problem :-)
I'm passing a hash to this function that either a) has keys that are strings along with values that are ints OR b) it is an empty hash.
The point of the function is to return nil if the hash is empty and return the key associated with the lowest int.
def key_for_min_value(name_hash)
if name_hash == nil
return nil
else
lowest_value = nil
lowest_value_name = nil
name_hash.collect do |name, value|
if lowest_value > value
lowest_value = value
lowest_value_name = name
end
end
return lowest_value_name
end
end
The error I'm receiving is:
1) smallest hash value does not call the `#keys` method
Failure/Error: key_for_min_value(hash)
NoMethodError:
undefined method `>' for nil:NilClass`
You can't compare nil to anything using >, it's not allowed, so you either have to avoid that test or use tools like min_by to get the right value instead of this collect approach.
One way to make your unit test happy might be:
def key_for_min_value(name_hash)
return unless (name_hash)
name_hash.keys.min_by do |key|
name_hash[key]
end
end
Ruby leans very heavily on the Enumerable library, there's a tool in there for nearly every job, so when you have some free time have a look around there, lots of things to discover.
Now Ruby is very strict about comparisons, and in particular a nil value can't be "compared" (e.g. > or < and such) to other values. You'll need to populate that minimum with the first value by default, not nil, then the comparisons work out, but doing that completely is pretty ugly:
def key_for_min_value(name_hash)
return unless (name_hash)
min_key, min_value = name_hash.first
name_hash.each do |key, value|
next unless (value < min_value)
min_key = key
min_value = value
end
min_key
end
So that approach is really not worth it. Enumerable makes it way easier and as a bonus your intent is clear. One thing you'll come to appreciate is that in Ruby if your code looks like code then you're probably going about it the wrong way, over-complicating things.
Ruby is an unusually expressive language, and often there's a very minimal form to express just about anything.
I've tried to put results from my vote model in a hash for further usage, but I don't know how to create a hash key from a variable in Ruby. See example below:
def create_hash_array(campaign_votes)
target_hash = Hash.new
campaign_votes.each_with_index do |cv,i|
target_hash[cv.content_id] = {} if i == 0
if target_hash[cv.content_id].member?(cv.vote_button_id)
target_hash[cv.content_id][cv.vote_button_id] = (target_hash[cv.content_id][cv.vote_button_id]).to_i + 1
else
target_hash[cv.content_id] = {cv.vote_button_id => nil}
end
end
target_hash
end
Usually I got an error:
undefined method `member?' for nil:NilClass
but it comes from unrecognized target_hash[cv.content_id], how can I make does variable to be recognized target_hash[cv.content_id] ??
I think your code can be boiled down to this:
def create_hash_array(campaign_votes)
target_hash = Hash.new { |h,k| h[k] = Hash.new(0) }
campaign_votes.each do |cv|
target_hash[cv.content_id][cv.vote_button_id] += 1
end
target_hash
end
There's multiple problems here, many to do with getting all tangled up in the process. You initialize the element of the target_hash structure only on the 0 index position, yet each campaign_vote could have different content_id values, meaning you're missing out on those.
This approach creates a single auto-generating Hash that will populate keys with counter hashes, that is hashes defaulting to 0. That means you can always navigate them and += 1 will work because of the default.
This approach is pretty common in Ruby, especially Hash.new(0), which is super handy for doing simple counters of arbitrary objects.
I keep getting 'no implicit conversion of String into Integer' when trying to run my model and the following;
def self.pull
fbstory = User.current.facebook.get_connection("me", "home")
fbstory.each do |story|
unless exists?(fb_id: story["id"])
User.current.new_fbtimeline_stories.create({fb_shares: story.first["shares"]["count"], fb_creation: story["created_time"], fb_message: story["message"], fb_status_type: 'new' })
end
end
end
and if I do this in the console it works fine but I need to do .each do |story|
fbstory = User.current.facebook.get_connection("me", "home").first
fbstory["shares"]["count"]
story is an array, and needs to be indexed numerically. You have story["created_time"]. You can't index arrays with strings. You need to use story.first['created_time'] as you have elsewhere on that line.
I'm working on a rake task which imports from a JSON feed into an ActiveRecord called Person.
Person has quite a few attributes and rather than write lines of code for setting each attribute I'm trying different methods.
The closest I've got is shown below. This works nicely as far as outputing to screen but when I check the values have actually been set on the ActiveRecord itself it's always nil.
So it looks like I can't use .to_sym to solve my problem?
Any suggestions?
I should also mention that I'm just starting out with Ruby, have been doing quite a bit of Objective-c and now need to embrace the Interwebs :)
http = Net::HTTP.new(url.host, url.port)
http.read_timeout = 30
json = http.get(url.to_s).body
parsed = JSON.parse(json)
if parsed.has_key? 'code'
updatePerson = Person.find_or_initialize_by_code(parsed['code'])
puts updatePerson.code
parsed.each do |key, value|
puts "#{key} is #{value}"
symkey = key.to_sym
updatePerson[:symkey] = value.to_s
updatePerson.save
puts "#{key}....." # shows the current key
puts updatePerson[:symkey] # shows the correct value
puts updatePerson.first_name # a sample key, it's returning nil
end
You're probably looking for update_attributes():
if parsed.has_key?('code')
code = parsed.delete('code')
person = Person.find_or_initialize_by_code(code)
if person.update_attributes(parsed)
puts "#{person.first_name} successfully saved"
else
puts "Failed to save #{person.first_name}"
end
end
Your code can not assign any attribute, because you are always assigning to the single attribute named "symkey":
symkey = key.to_sym
updatePerson[:symkey] = value.to_s # assigns to attribute "symkey", not to the attribute with the name stored in variable symkey
If you want to make key into a symbol (which is probably not even necessary) and then use that as an index to access the attribute in updatePerson, you can write:
updatePerson[key.to_sym] = value.to_s
updatePerson.save
But this - more or less - is the same as
updatePerson.updateAttribute(key.to_sym, value.to_s) # update and save
except that no validation is triggered, so use with care.
And performancewise it might not be such a good idea to save the person after each assignment, so maybe you want to defer the .save() call until after you have assigned all attributes.
Nevertheless, updateAttributes(...) is something you might want to be looking into - if you do, do not forget to inform yourself on attr_protected or attr_accessible, as they protect attributes from "bulk assignment"
You can use write_attribute:
parsed.each do |key, value|
updatePerson.write_attribute(key, value)
end
updatePerson.save