MongoMapper, increment and update other attributes at the same time? - ruby-on-rails

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.

Related

Active record querying with store_accesors

I have a database where I need to do a search on specific record that has a certain output. What is making this tricky for me is that these values are found in a 'store_accessor' and therefore they aren't always there.
For instance if I run Team.last.team_configuration, I get this value below, and what I need are only teams that have a specific setting.
<TeamConfiguration:0x00007123456987> {
:id => 8,
:owner_id => 6,
:team_type => "football",
:settings => {
"disable_coach_add" => false,
"delink_players_at_18" => true
},
:type => "TeamConfiguration"
}
My thoughts have been something around these lines, but i keep getting undefined method 'settings' for team_configuration:Symbol
Team.where(:team_configuration.settings['delink_players_at_18'])
Would anyone know what I am doing wrong in this instance? I think because there are two separations from the main source it has been causing me some issues. Thanks in advance!
The problem is way store_accesors works, look what documentation says:
Store gives you a thin wrapper around serialize for the purpose of
storing hashes in a single column. It's like a simple key/value store
baked into your record when you don't care about being able to query
that store outside the context of a single record.
https://api.rubyonrails.org/classes/ActiveRecord/Store.html
So a posible solution could be to search by that column, converting a previously hash of what you want to string.
Team.where(team_configuration: data.to_s)
If you're using a postgres database and the TeamConfiguration#settings column is serialized as jsonb column you can get at this with postgres json operators:
Team.joins(:team_configurations)
.where("team_configurations.settings #> '{\"delink_players_at_18\": true}'")

Cassandra and creating an int column name from Ruby client

I am attempting to create dynamic columns with a comparator/validator that is a 32 bit signed integer. This obviously will save on storage space amongst other advantages. Currently, this works great if I have a UTF8Type validator (Using Twitter's cassandra client for Ruby):
db.insert(:foo, 'mykey', {'mycol' => 'myval'})
This is where the problem occurs:
db.insert(:foo, 'mykey', {5 => 'myval'})
I think this is more of a Ruby issue than Cassandra issue. Using Rails console, I get the following thrown out at me:
TypeError: no implicit conversion of Fixnum into String
Further clarification, I can't simply do:
db.insert(:foo, 'mykey', {'5' => 'myval'})
This will trigger a validation fail which is expecting an integer for the column and not a string.
Is there a way to make this reasonably work in Ruby so that I don't have to use UTF8Type column names and can stick to int based ones for my Cassandra 1.2 based app?
The twitter Cassandra library leaves it to you the developer to serialize/deserialize all values. It requires everything that you give it to be in binary string representation. So if you want to use ints as your comparator you need to pack them before inserting and unpack them when fetching them out of Cassandra. Your insert needs to look like this:
db.insert(:foo, 'mykey', {[5].pack('N*') => 'myval'})
#MrYoshiji
Fixnum CAN be declared as key in Ruby Hashes.
Just use correct syntax. You're in Ruby, not Python !!!
irb(main):010:0> { 1 => 'bonjour', 2 => "okay" }
=> {1=>"bonjour", 2=>"okay"}
irb(main):012:0> { 1 => 'bonjour', 2 => "okay" }.keys.map(&:class)
=> [Fixnum, Fixnum]

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.

Java ArrayList in Ruby

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.

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