I have an array with keys that I use to create options for a drop down
FEEDBACK_NOTIFICATION = [['Only in reports', 'only_in_reports'],['Immediately', 'immediately']]
<%= f.select(:feedback_schedule, options_for_select(FEEDBACK_NOTIFICATION)) %>
The first values ('Only in reports', 'Immediately') are displayed in the drop down but the last value is stored in the database ('only_in_reports' or 'immediately').
When I want to show the value in a view I am doing something like this:
REPORT_SCHEDULE.select {|v,k| k==#company.report_schedule}.first.first
Is there not an easier way to retrieve a value from a key pair array?
Slightly better:
REPORT_SCHEDULE.find { |v, k| k == #company.report_schedule }.first
Personally, I would however store the "translations" in a yaml file, following the I18n conventions, as shown in my answer on question Translating activerecord collection for a dropdown
This way, your "representation" is nicely separated from the rest of your code
This should do.
Hash[REPORT_SCHEDULE][#company.report_schedule]
Related
My goal is to determine whether there is a blank in a hash like this:
{"departure_time_slots"=>{"date"=>[""], "time"=>{"start"=>[""], "end"=>[""]}}}
The strings are nested arbitrary times. I do not want to check each of them manually. It would be nice if I can extract all the strings regardless of their depth. Is there a simple way to do that?
Here's an example of how you can extract the values. However you will still have the problem of matching the values to the keys. You can't really have both at the same time.
# Extend the Hash class
class Hash
def recursive_values
self.values.collect { |v|
v.is_a?(Hash) ? v.recursive_values : v
}.flatten
end
end
Usage:
h = {"departure_time_slots"=>{"date"=>[""], "time"=>{"start"=>[""], "end"=>[""]}}}
h.recursive_values
=> ["", "", ""]
It will be better if you will use sth like that:
departure_time_slots = {:date => Time.new, :time_start => nil, :time_end => nil}
And when you use keys in Hash it is good practise to using Symbols for keys. (http://www.ruby-doc.org/core-1.9.3/Symbol.html)
No not possible. Because they are totally present in different scope with respect to each other.
For e.g.. keys start and end is totally unknown and masked from the departure_time_slots object in the example above.
One round abut way could be, getting all the values of the hashmap which are of type hashmap again and obtaining their keys recusively.
Fetch keys of departure_time_slots and then from the value list of that map, find all the keys from every value, if that were to be a hashmap. Other than that, I don't think there is another way.
P.S. On side note, see if u can modify your structure to an array where elements can also be arrays, and try and use flatten concept of arrays. :P
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.
I'm implementing a form based on Ryan Bate's [always excellent] Railscast, #52, Update Through Checkboxes, http://railscasts.com/episodes/52-update-through-checkboxes
In my case, I'm actually wanting to pass through an array of ids for each checkbox selected.
The key line in my form looks like this,
<td"><%= check_box_tag "sales_ids[]", batch["sales_ids"] %></td>
batch["sales_ids] itself is an array of ids, and the outcome I'm wanting is for an array of all the checked items (each representing an array of ids) to be passed along.
If I inspect the individual batch["sales_ids"] from the form, then I can confirm it is indeed an array, for example, [3907, 3908, 3909] (remember, I want to pass along an array of these items for each row checked)
The key line from the method that handles the form looks like this,
params[:sales_ids].each { |batch| Sales.update_all(["code=?", 99], :id => batch) }
The intent of this code, again based on the Railscast example, is to iterate over the array of arrays, and update each sub-array of ids.
When I examine the received array, I see, ["5412", "3907 3908 3909", "2452"]
The sub-array isn't handled as an array and (for reasons I don't understand) only the first item each 'substring' (in this case "5412", "3907", "2452") is updated.
It seems that the passed subarray isn't actually an array, or something else is awry.
I'd appreciate help in how to pass and receive these ids as an array of arrays. Thanks.
as far as I know, passing arrays of arrays in this way won't work via a form. However there is a work around that should work fine for you.
in the view do this for your checkboxes: (I'm assuming batch["sales_ids"] is an array)
<%= check_box_tag "sales_ids[]", batch["sales_ids"].join(",") %>
And in your controller do this:
params[:sales_ids].collect{|a| a.split(",") }.each { |batch| Sales.update_all(["code=?", 99], :id => batch) }
Instead of passing an array of arrays, we are now passing an array of comma separated values. In the controller these comma separated values are turned into an array.
I have a hash that will render my html differently based on a particular variable. The variable is within the hash. So I am wondering how I can pass a hash value to a group by. to sort the rest heres what I am trying, maybe this will explain it better than me wording it.
<% grouped = svcs.group_by { |svc| svc[val[:sorttype]] } %>
val is a multidimensional hash. the first 2 key value pairs sorttype and one other are simple key and value, the 3rd piece (svcs) contains the equivilent of a 2D hash. Which if I manually type the type of sort I want to apply to it for the group by it works ie:
<% grouped = svcs.group_by { |svc| svc[:service_name] } %>
in PHP i know in a similar instance I can pass a variable of some sort to something like this and have it work. I assume such is the case here. However Im not sure how to put the variable in. Cause all the ways Ive tried don't work
It depends a little.
Rails' has a HashWithIndifferentAccess that will not distinguish between string and symbol keys; if you're using one of those, it should work as-is.
If it's not, it depends what the val entries are--if they're strings, convert to a symbol using to_sym, e.g., svc[val[:sorttype].to_sym].
I'm building an xml document from a hash. The xml attributes need to be in order. How can this be accomplished?
hash.to_xml
Ruby 1.8's hash aren't in insertion order. With ruby 1.9, they will be.
However rails offers an alternative to that, the class OrderedHash.
my_hash = ActiveSupport::OrderedHash.new
my_hash[:key] = 'value'
my_hash[:second_key] = 'second value'
This hash is in fact an array of that format :
[[:key, 'value'], [:second_key, 'second value']]
The entries remains in the order you inserted them.
And you can access them like with any other hash.
h = Hash[:x,123,:a,553,:d,949,:e,5321]
=> {:e=>5321, :x=>123, :a=>553, :d=>949}
h.sort { |x,y| x[0].to_s <=> y[0].to_s }
=> [[:a, 553], [:d, 949], [:e, 5321], [:x, 123]]
The usual ways of sorting a hash is by key or value. Have a look here:
hash.sort
More complex sorts can be accomplised however by utilizing the spaceship operator
What order did you want them to be in? You shouldn't expect them to be in insertion order. From the docs for Hash:
The order in which you traverse a hash
by either key or value may seem
arbitrary, and will generally not be
in the insertion order.
If you need them to be in a specific order you can determine just from the keys/values (e.g. order the attribute names alphabetically), you'll need to apply that ordering explicitly.
This piece of code I've just made for i18n-js might help you out as it convert Hash to ActiveSupport::OrderedHash if needed then sort it's key by natural order.
http://seb.box.re/2010/1/15/deep-hash-ordering-with-ruby-1-8