I feel like I'm missing something really obvious here.
I have the following hash placed in variable "simple_lable". Calling inspect on it works fine, but I cannot seem to access any of the numerical values. .to_i comes out as 0, .to_f comes out as 0.0 and to_s comes out blank
puts "**************************"
puts simple_label.inspect
puts simple_label["margin_top"].to_f
puts simple_label["margin_bottom"].to_f
puts simple_label["margin_right"].to_f
puts simple_label["margin_left"].to_f
puts simple_label["paper_size"]
puts "**************************"
results in
**************************
{"paper_size"=>"LETTER", "top_margin"=>36, "bottom_margin"=>36, "left_margin"=>15.822, "right_margin"=>15.822, "columns"=>3, "rows"=>10, "column_gutter"=>15, "row_gutter"=>0}
0.0
0.0
0.0
0.0
LETTER
**************************
So the values are there, but I just can't seem to get hold of them correctly.
Any ideas?
Many thanks.
The problem is that your hash keys are incorrect. Your hash has, for example, top_margin, as a key, but you are trying to reference a key of margin_top. The hash will return nil for a non-existent key, and to_f, to_i are giving zero, and to_s giving blank for a nil hash value.
Related
I'm newbie in ruby on rails, trying to rewrite rails project in PHP, can someone explain me please what next lines of code do?
def payment_types_billing
I18n.t("customer.payment_types_billing").inject({}){|memo,(k,v)|
memo[k.to_s.to_i] = v; memo}.
merge({
PaymentType::ACCOUNTCREDIT => I18n.t("customer.payment_types_billing.#{PaymentType::ACCOUNTCREDIT}",
:amount => number_to_currency(get_account_credit))
})
end
I don't understand part after .inject, if someone can just explain that part in human language, I will be very thankful. :)
These methods work in conjunction. By calling payment_types, the following will occur:
First it grabs a section of the localization yaml (likely in config/locales/en.yml). For more on internationalization/localization, see this!
I18n.t("customer.payment_types_billing")
Then it runs an inject block on the resulting enumerable (in this case a hash), with the intent of returning a newly-formed result (see about .inject here)
.inject({}){|memo,(k,v)| memo[k.to_s.to_i] = v; memo}
The result of this block appears to be a hash whose keys were the keys of the retrieved hash, converted to integers (without knowing the data being accessed, I can't know how this is meant to function).
Addendum:
I suspect the purpose of the above block is to assign integer keys to a new hash (something that is impossible otherwise). Seeing the later steps with the invert, this would mean that the final printed hash will have integer values, not strings.
It then adds two new key value pairs to the hash:
.merge({PaymentType::ACCOUNTCREDIT => I18n.t("customer.payment_types_billing.#{PaymentType::ACCOUNTCREDIT}", :amount => number_to_currency(get_account_credit))})
The first pair has a key equal to ACCOUNTCREDIT, with another value retrieved from the YAML. The second is the key :amount, with the value of "get_account_credit" (presumably a method with a decimal output) converted to currency for the current region.
As we reach the actual content of the payment_types method, the results from above (the newly-formed hash) is a block with a delete condition. If get_account_credit is returning a non-positive number, the ACCOUNTCREDIT keyed pair is deleted
.delete_if {|key, value| (key == PaymentType::ACCOUNTCREDIT && get_account_credit <= 0) }
Finally, the hash is inverted (the keys become the values, and the values become the keys):
.invert
I've got an hash that looks like this
{"1-5 lbs"=>107342.43999999999, "31+ lbs"=>39838.58000000001, "21-30 lbs"=>19036.41, "11-20 lbs"=>39350.95, "6-10 lbs"=>41401.880000000005}
And I'd like to sort it so it looks like this
{"1-5 lbs"=>107342.43999999999, "6-10 lbs"=>41401.880000000005, "11-20 lbs"=>39350.95, "21-30 lbs"=>19036.41, "31+ lbs"=>39838.58000000001 }
The logic is being stored in an instance variable #weight_ranges
You'll need to get into regular expressions to get the value of the first number of each
range.
Hash[(#weight_ranges.sort_by {|key, value| key.scan(/\d+/)[0].to_i})]
To break it down further:
# Sort the weight ranges by the first series of digits found in the key
x = #weight_ranges.sort_by {|key, value| key.scan(/\d+/)[0].to_i}
# Convert each inner Array to a key, value pair in a Hash
x = Hash[x]
You depicted the data as a hash. For a sequence you'll need an array of pairs. Something like this will do it:
list_of_pairs = #weight_ranges.keys.sort_by(&:to_i).map {|k| [k, #weight_ranges[k]]}
This exploits a happy coincidence that to_i stops at the first non-digit it sees.
Correction
I have just learned that in 1.9 Ruby hashes are ordered! So it's easy to adapt:
Hash[#weight_ranges.sort_by{|k,v| k.to_i}]
I'll leave both ideas here, since the first one is still right for Ruby < 1.9.
After gathering data from a web service, I'm trying to pull out only those records that have a value for a particular field > 0. The field that I'm checking is a FixNum field. I have tried multiple things like .nil? or > 0 etc. But none of them seem to work.
Here is how the code goes:
results.each do |r|
# puts "came"
if r['efforRemaining'] % 1 != 0 #i tried r['efforRemaining'].nil? ..
# i have values like 0.4, 0.5 etc for the field, hence i need to check if the value is greater than 0 or not only
puts "came!"
puts "#{r['mstone']} ... #{r['assignee']['id']} ... #{r['effortRemaining'].to_f}"
end
end
Could somebody let me know how to do this?
thanks,
If puts r['effortRemaining'].inspect comes out in quote marks, that means it is a string and you need to convert it to a number before you compare it.
This should work:
if r['effortRemaining'].to_f > 0
I have an AR query that returns a hash of events per month, ordered by month
o.events.group("to_char(date,'MM')").order("to_char(date,'MM')").size()
I'm using numeric months in this query as it was the best way I could find to get things in the correct order, and I also need to do some other manipulations on the hash.
Before display the results, I need to convert the numeric months back to words. I added the following to the end of the query
.each_key{ |key| Date::MONTHNAMES[key] }
But i get
TypeError: can't convert String into Integer.
So i tried
.each_key{ |key| Date::MONTHNAMES[key.to_i] }
But the months remain in numeric form
{"01"=>4, "02"=>3.....
How can i manipulate this hash to get
{"January"=>4, "February"=>3.....
Make a new Hash. If you can't, make a new key in the current hash and delete the original key. You can't simply change a key, since key is a local variable in the block, and changing it in no way impacts the contents of the Hash.
This ? :
def number_to_month(number)
(Time.now.beginning_of_year + number.months).strftime("%B")
end
There are ways to generate a new hash but I think you could just convert the strings to month names in your view right before displaying them. Use the code you already wrote inside the block in your question but put it in your view.
This seems very strange to me, an active record sum returns a string, not a number
basket_items.sum("price")
This seems to make it work, but i thought i may have missed something, as this seems like very strange behaviour.
basket_items.sum("price").to_i
According to the (rails 2.3.9) API:
The value is returned with the same data type of the column, 0 if there’s no row
Could your price column be a string or text?
https://github.com/rails/rails/pull/7439
There was a reason it returned a string - calling to_d on a Fixnum in Ruby 1.8 would give a NoMethodError. This is no longer the case in Ruby 1.9 so it's probably okay to change.
ActiveRecord sum:
Difference:
1) basket_items.sum("price")
It will also sum non integer also and it will return non integer type.
2) basket_items.sum("price").to_i
This above will convert into integer.
# File activerecord/lib/active_record/relation/calculations.rb, line 92
def sum(*args)
if block_given?
self.to_a.sum(*args) {|*block_args| yield(*block_args)}
else
calculate(:sum, *args)
end
end
Calculates the sum of values on a given column. The value is returned with the same data type of the column, 0 if there’s no row.
http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html#method-i-sum
Github:
https://github.com/rails/rails/blob/f8f4ac91203506c94d547ee0ef530bd60faf97ed/activerecord/lib/active_record/relation/calculations.rb#L92
Also see, Advanced sum() usage in Rails.