Java ArrayList in Ruby - ruby-on-rails

When I submit the form to server, Rails.logger.info params
gives
{"cgAttr"=>{"1"=>"abc,pqr", "2"=>"US"}}
and I want
{"cgAttr"=>{"1"=>"abc", "1" => "pqr", "2"=>"US"}}
PS. "1" is input text box in UI that take multiple comma-separate values ("abc,pqr") and on server I am converting that entire string into array (["abc", "pqr"]).
Can Any one point me in correct direction?
Basically, I want to create ArrayList similar to Java in my Ruby on Rails application. Does anyone know how to achieve it. (I have not tried JRuby plugin yet)

The easiest answer is to use split:
arr = params[:cgAttr]["1"].split(",")
(Also not psyched about using "1" as a parameter name.)

Can't be done, hash key must be a unique value:
{:foo => 'foo1', :foo => 'foo2'} #=> {:foo => 'foo2'}
Think about it, how would you differentiate between the two elements? my_hash[:foo] can only refer to one element, but if two elements have the same :foo key how can you distinguish between the two?
I like Dave Newtons answer, because then you can actually access them, e.g.:
my_hash[:foo][0], my_hash[:foo][1]

It can be done:
h = {}
h.compare_by_identity
a = "1"
b = "1"
h[a] = "abc"
h[b] = "pqr"
p h # {"1"=>"abc", "1"=>"pqr"}
but it doesn't feel right.

Related

How to rename a symbol in hash parameters?

I have parameters from an external API that formats JSON responses using CamelCase that I want to fit into my Rails app:
{"AccountID"=>"REAWLLY_LONG_HASH_API_KEY_FROM_EXTERNAL_SERVICE",
"ChannelProductDescription"=>"0004", "Currency"=>"CAD",
"CurrentBalance"=> {"Amount"=>"162563.64", "Currency"=>"CAD"}}
Using the below script I converted them to lower case:
data = JSON.parse(response, symbolize_keys: true)
data = {:_json => data} unless data.is_a?(Hash)
data.deep_transform_keys!(&:underscore)
data.deep_symbolize_keys!
Leaving me correctly formatted params like this:
{:account_id=>"REAWLLY_LONG_HASH_API_KEY_FROM_EXTERNAL_SERVICE",
:channel_product_description=>"SAVINGS", :currency=>"CAD",
:current_balance=> {:amount=>"43.00", :currency=>"CAD"}}
I'm trying to map this external API response into a generic Rails model Account, where JSON from this API call will return cleanly as parameters into my database to allow a clean saving interface such as:
#account = Account.create(ParamParser.call(params))
But I ran into a problem with converting :account_id, as that param conflicts with the primary key of my database.
To get around this, my idea is to convert all symbol instances of params[:account_id] into params[:account_key_id], so that those params don't conflict with my databases existing account_id field.
How do I do this, and is there a better approach for consuming external JSON API's than what I've described here?
Hash#deep_transform_keys does this:
Returns a new hash with all keys converted by the block operation.
This includes the keys from the root hash and from all
nested hashes and arrays.
So you could do it in one pass with an appropriate block, something like:
data.deep_transform_keys! do |key|
key = key.underscore.to_sym
key = :account_key_id if(key == :account_id)
key
end
You might as well drop the symbolize_keys: true flag to JSON.parse too, you're changing all the keys anyway so don't bother.
If you're doing this sort of thing a lot then you could write a method that takes a key mapping Hash and gives you a lambda for transforming the keys:
def key_mangler(key_map = { })
->(key) do
key = key.underscore.to_sym
key = key_map[key] if(key_map.has_key?(key))
key
end
end
and then say things like:
data.deep_transform_keys!(&key_mangler(:account_id => :account_key_id))
You might want to use a different name than key_mangler of course but that name is good enough to illustrate the idea.
BTW, if you're sending this JSON into the database then you probably don't need to bother with symbol keys, JSON only uses strings for keys so you'll be converting strings to symbols only for them to be converted back to strings. Of course, if you're symbolizing the keys when pulling the JSON out of the database then you'll probably want to be consistent and use symbols across the board.
In addition to the previous answer...
Unfortunately, there is, to my knowledge, no method on Hash that does this in one operation. I've always accomplished this by brute force, as in:
hash[:new_key] = hash[:old_key]
hash.delete(:old_key)
A shortcut for this, suggested in the comment below by "mu is too short", is:
hash[:new_key] = hash.delete(:old_key)
To illustrate in irb:
2.4.1 :002 > h = { foo: :bar }
=> {:foo=>:bar}
2.4.1 :003 > h[:foo_new] = h.delete(:foo)
=> :bar
2.4.1 :004 > h
=> {:foo_new=>:bar}

Rails generate link with array parameter

Need an advice how to generate list of links with array of paramenter
/controller/action/id?pid1=1001&vid1=1002&pid2=2001&vid2=2002
/controller/action/id?pid1=1001&vid1=1002&pid2=2001&vid2=2003
/controller/action/id?pid1=7001&vid1=7002&pid2=2001&vid2=2003
Where pid is id of filter type, and vid is id of filter value.
What I assume you have is parameters in an array like so
params_array = ["a","b","c", "d"] where the first parameter is pid1, second is vid1, third is pid2, fourth is vid2
if this is the setup, then try this:
link_to "this is some link text", some_path, :pid1 => params_array[0], :vid2 => params_array[1] %>
etc... there are better ways to do this with loops/etc. to format the params better, but in order to do so I need to know how your original params are like.
EDIT: Again, I'm really not sure how your data is formatted so for me to be able to give you any more useful help, you'll need to expand the question with more data.
What I can tell you though is that if you wanted to have a loop to go through and merge the params, you could do so like this:
pid_parameters = params_array.each_with_index.map {|e, i| {"#{i%2==0 ? "pid" : "vid"}#{i+1}" => a[i]}}
and then link_to "this is some link text", some_path, pid_parameters which will produce something like:
/controller/action/id?pid1=1001&vid2=1002&pid3=2001&vid4=2002
again, give some more information for this to be relevant. Thanks

Is there a way to skip serialization in Rails 3.1?

In my Rails 3.1 application, I need to read the raw data of a field, without serialization, and then write it down without serialization. Is this possible? How?
By serialization I mean
class Tenant
serialize :profile_template
end
I obviously can access the field like this:
> t.profile_template
=> [{:title=>"Page 1", ....}]
I then also tried with read_attribute_before_type_cast (as per lucapette's suggestion):
> t.read_attribute_before_type_cast(:profile_template)
=> nil
Using a string instead of a symbol had a different but disappointing result:
> t.read_attribute_before_type_cast("profile_template")
=> [{:title=>"Page 1", ...}]
and same with the attribute name:
> t.profile_template_before_type_cast
=> [{:title=>"Page 1", ...}]
Just for the record, what I was expecting is:
"---
- :title: Page 1
...."
In all samples, ... is the rest of a very long structure.
Yes there is a way. You have to use
read_attribute_before_type_cast(:foo)
where :foo is the name of the field. The doc is not that good about that but I remember that there is a good explanation about it in The Rails 3 way.
EDIT
Although you're saying that this way isn't working for you I re-read the piece of information from the above-mentioned book. Well, there's another way of doing that. You can use
bar = foo_before_type_cast
where foo is the name of the field. It works like magic finders, pre-pending the name of the field to _before_type_cast . I can't try it right now but it really should work fine.

MongoMapper, increment and update other attributes at the same time?

How do I do the following in one operation:
Find or create object by some key:value pairs
Increment properties on the object.
I am doing this now:
Model.find_or_create_by_this_and_that(this, that).increment("a" => 1, "b" => 1)
What's the correct way to do that?
From javascript you should be able to do something like
db.model.update({"_id" : "xyz"}, {$inc : {"a":1,"b":1} })
It looks like the MongoMapper equivalent is
Model.collection.update({"_id" => self._id}, {"$inc" => {"a" => 1,"b" => 1}})
MongoMapper also seems to support an increment feature, but I'm unfamiliar with the syntax. In either case that second command looks very similar to the javascript version (and the php version), so that's probably what you're looking for.

Parse a string as if it were a querystring in Ruby on Rails

I have a string like this:
"foo=bar&bar=foo&hello=hi"
Does Ruby on Rails provide methods to parse this as if it is a querystring, so I get a hash like this:
{
:foo => "bar",
:bar => "foo",
:hello => "hi"
}
Or must I write it myself?
EDIT
Please note that the string above is not a real querystring from a URL, but rather a string stored in a cookie from Facebook Connect.
The answer depends on the version of Rails that you are using. If you are using 2.3 or later, use Rack's builtin parser for params
Rack::Utils.parse_nested_query("a=2") #=> {"a" => "2"}
If you are on older Rails, you can indeed use CGI::parse. Note that handling of hashes and arrays differs in subtle ways between modules so you need to verify whether the data you are getting is correct for the method you choose.
You can also include Rack::Utils into your class for shorthand access.
The
CGI::parse("foo=bar&bar=foo&hello=hi")
Gives you
{"foo"=>["bar"], "hello"=>["hi"], "bar"=>["foo"]}
Edit:
As specified by Ryan Long this version accounts for multiple values of the same key, which is useful if you want to parse arrays too.
Edit 2:
As Ben points out, this may not handle arrays well when they are formatted with ruby on rails style array notation.
The rails style array notation is: foo[]=bar&foo[]=nop. That style is indeed handled correctly with Julik's response.
This version will only parse arrays correctly, if you have the params like foo=bar&foo=nop.
Edit : as said in the comments, symolizing keys can bring your server down if someone want to hurt you. I still do it a lot when I work on low profile apps because it makes things easier to work with but I wouldn't do it anymore for high stake apps
Do not forget to symbolize the keys for obtaining the result you want
Rack::Utils.parse_nested_query("a=2&b=tralalala").deep_symbolize_keys
this operation is destructive for duplicates.
If you talking about the Urls that is being used to get data about the parameters them
> request.url
=> "http://localhost:3000/restaurants/lokesh-dhaba?data=some&more=thisIsMore"
Then to get the query parameters. use
> request.query_parameters
=> {"data"=>"some", "more"=>"thisIsMore"}
If you want a hash you can use
Hash[CGI::parse(x).map{|k,v| [k, v.first]}]

Resources