Duplicated searchkick index for a single record - ruby-on-rails

I have a model User that I am indexing in ElasticSearch through Searchkick:
class User < ActiveRecord::Base
searchkick callbacks: :async, routing: true
end
Also I have a background job to reindex conditionally.
The problem is that in some case I have repeated indexes for a single user:
2.3.8 :191 > u = User.find_by_email("john.doe#mail.com")
=> #<User id: 401953, email: "john.doe#mail.com", name: "John Doe", university_id: 83, device_id: "b3f3d62839ca6b981ea236562e6da9ff", app_version: "6.7.0>
But I am having repeated searchkick indexes with the same id and _index!
2.3.8 :192 > ap User.search("*", where: {email: "john.doe#mail.com"}, load: false).results
[
[0] {
"_index" => "users_production_20200717081323100",
"_type" => "user",
"_id" => "401953",
"_score" => 1.0,
"_routing" => "123",
"email" => "john.doe#mail.com",
app_version" => "6.6.0",
"id" => "401953"
},
[1] {
"_index" => "users_production_20200717081323100",
"_type" => "user",
"_id" => "401953",
"_score" => 1.0,
"_routing" => "123",
"email" => "john.doe#mail.com",
app_version" => "6.7.0",
"id" => "401953"
}
]
The only attribute that changes is the app_version. In some moment the user had "6.6.0" version and when update to 6.7.0 the index was repeated. In this case, why is happening this? is this the normal behavior of the gem?. Shouldn't it be updated and leave a single index?
Regards

Related

monogid pluck returns duplicate results for embedded/nested fields

Monogoid pluck returns duplicate embedded results (not concerned about duplicate rows) for embedded fields.
eg: (user is embedded document for SomeModel)
SomeModel.where(condition).pluck(:region, "user.name", "user.lastname")
Results:
[["amr",
{"name" => "mark", "lastname" => "goodman"},
{"name" => "mark", "lastname" => "goodman"}],
["amr",
{"name" => "john", "lastname" => "cena"},
{"name" => "john", "lastname" => "cena"}]
]
I was expecting something like below:
[["amr",
{"name" => "mark"},
{"lastname" => "goodman"}],
["amr",
{"name" => "john"},
{"lastname" => "cena"}]
]
Similarly, if I query multiple fields from embedded doc, it creates that many duplicate hashes.
Not sure if I am doing something wrong here.
I'm not sure why that's the case, but you can get the desired result using map instead of pluck:
SomeModel.where(condition).map { |m| [m.region, m.user.name, m.user.lastname] }
This should give you the results:
[
["amr", "mark", "goodman"],
["amr", "john", "cena"]
]
Or:
SomeModel.where(condition).map do |m|
[m.region, { 'name' => m.user.name }, { 'lastname' => m.user.lastname }]
end
Should give you the results:
[
["amr", { "name" => "mark" }, { "lastname" => "goodman" }],
["amr", { "name" => "john" }, { "lastname" => "cena" }]
]

Grabbing a specific hash in an array that meets a specific criteria

I have a huge array full of a bunch of hashes. What I need to do is single out one index hash from the array that meets a specific criteria. (doing this due to an rspec test, but having trouble singling out one of them)
My array is like this
[
{
"name" => "jon doe",
"team" => "team2",
"price" => 2000,
"eligibility_settings" => {}
},
{
"name" => "jonny doe",
"team" => "team1",
"value" => 2000,
"eligibility_settings" => {
"player_gender" => male,
"player_max_age" => 26,
"player_min_age" => 23,
"established_union_only" => true
}
},
{
"name" => "jonni doe",
"team" => "team3",
"price" => 2000,
"eligibility_settings" => {}
},
]
I need to single out the second one, based on its eligibility settings. I just took three of them from my array, have lots more, so simple active record methods like (hash.second) won't work in this instance.
I've tried things like
players.team.map(&:hash).find{ |x| x[ 'eligibility_settings?' ] == true}
However when I try this, I get a nil response. (which is odd)
I've also looked into using the ruby detect method, which hasn't gotten me anywhere either
Players.team.map(&:hash).['hash.seligibiltiy_settings'].detect { true }
Would anybody have any idea what to do with this one?
Notes
players.team.map(&:hash).find{ |x| x[ 'eligibility_settings?' ] == true}
Players.team.map(&:hash).['hash.seligibiltiy_settings'].detect { true }
Is is players or Players ?
Why is it plural?
If you can call map on team, it probably should be plural
Why do you convert to a hash?
eligibility_settings? isn't a key in your hash. eligibility_settings is
eligibility_settings can be a hash, but it cannot be true
If you want to check if it isn't empty, use !h['eligibility_settings'].empty?
Possible solution
You could use :
data = [
{
'name' => 'jon doe',
'team' => 'team2',
'price' => 2000,
'eligibility_settings' => {}
},
{
'name' => 'jonny doe',
'team' => 'team1',
'value' => 2000,
'eligibility_settings' => {
'player_gender' => 'male',
'player_max_age' => 26,
'player_min_age' => 23,
'established_union_only' => true
}
},
{
'name' => 'jonni doe',
'team' => 'team3',
'price' => 2000,
'eligibility_settings' => {}
}
]
p data.find { |h| !h['eligibility_settings'].empty? }
# {"name"=>"jonny doe", "team"=>"team1", "value"=>2000, "eligibility_settings"=>{"player_gender"=>"male", "player_max_age"=>26, "player_min_age"=>23, "established_union_only"=>true}}
If h['eligibility_settings'] can be nil, you can use :
data.find { |h| !h['eligibility_settings'].blank? }
or
data.find { |h| h['eligibility_settings'].present? }

How to send correctly a JSON request testing Rails?

I'm witnessing an odd behavior in Rails, when sending a post request, with the following body:
If you check is a Hash (converted to JSON when sending). But ODDLY when being read by params in controller, is recognized like this:
If you check carefully, the attributes of :first_name and :email are moved to the previous item in the array.
I'd thought if you have an array with certain attributes on the first item, but some different attributes on the following items, the array would be respecting the positions of which the attributes are set for.
I know most likely the answer would be "just put a nil or empty value of those attributes on the first item of the array", but I'm more interested in the reason of why this is happening.
Thank you.
UPDATE
Thanks to a question, I replicated the scenario form a browser (I was originally doing the request from the test feature of rails), and checking the Network from the browser, this is what is being sent:
{
"name": "un nombre",
"team_members": [
{
"user_id": 1,
"team_member_role_id": 4
},
{
"email": "cpamerica#avengers.com",
"first_name": "Cap America",
"team_member_role_id": 4,
"admin": true
},
{
"email": "hulk#avenrgers.com",
"first_name": "Bruce Banner",
"team_member_role_id": 1,
"admin": false
},
{
"email": "ironman#avengers.com",
"first_name": "Tony Stark",
"team_member_role_id": 1,
"admin": false
},
{
"email": "thor#avengers.com",
"first_name": "Thor Hijo de Odín",
"team_member_role_id": 2,
"admin": false
}
]
}
And it works. So I focused on how I was sending the info from the test environment, this is the actual code:
team = {
:name => 'un nombre',
:team_members => [
{
:user_id => 1,
:team_member_role_id => TeamMemberRole.role_communicator_id
},
{
:email => 'cpamerica#avengers.com',
:first_name => 'Cap America',
:team_member_role_id => TeamMemberRole.role_communicator_id,
:admin => true
},
{
:email => 'hulk#avenrgers.com',
:first_name => 'Bruce Banner',
:team_member_role_id => TeamMemberRole.role_visionary_id,
:admin => false
},
{
:email => 'ironman#avengers.com',
:first_name => 'Tony Stark',
:team_member_role_id => TeamMemberRole.role_visionary_id,
:admin => false
},
{
:email => 'thor#avengers.com',
:first_name => 'Thor Hijo de Odín',
:team_member_role_id => TeamMemberRole.role_developer_id,
:admin => false
}
]
}
post create_team_path, :team => team, :format => :json
And what is being read in the controller by request.raw, this is what is getting (using the debugger):
team[name]=un+nombre&
team[team_members][][user_id]=1&
team[team_members][][team_member_role_id]=4&
team[team_members][][email]=cpamerica%40avengers.com&
team[team_members][][first_name]=Cap+America&
team[team_members][][team_member_role_id]=4&
team[team_members][][admin]=true&
team[team_members][][email]=hulk%40avenrgers.com&
team[team_members][][first_name]=Bruce+Banner&
team[team_members][][team_member_role_id]=1&
team[team_members][][admin]=false&
team[team_members][][email]=ironman%40avengers.com&
team[team_members][][first_name]=Tony+Stark&
team[team_members][][team_member_role_id]=1&
team[team_members][][admin]=false&
team[team_members][][email]=thor%40avengers.com&
team[team_members][][first_name]=Thor+Hijo+de+Od%C3%ADn&
team[team_members][][team_member_role_id]=2&
team[team_members][][admin]=false&
format=json
Any idea on why the index of each team_member is missing? Am I sending the array wrong?
To send an acceptable json request you need to send as a formed String instead the hash, also add the headers
your code must look something like this:
post create_team_path, {:team => team}.to_json, 'CONTENT_TYPE' => 'application/json;charset=utf-8'
Note the problem is within the parser hash to form-request not adding the index of each object
Source: How to post JSON data in rails 3 functional test

add two parameters in Soulmate::Loader

i have two fields in my model and i want add them in Soulmate::Loader:
for example, my "person" model has name and email field. and i want load then in Soulmate:
loader = Soulmate::Loader.new("people")
loader.add("term" => name, "id" => self.id, "data" => {
"link" => Rails.application.routes.url_helpers.person_path(self)
})
i want add name and email in loader.add. but i can't.
def load_into_soulmate
loader = Soulmate::Loader.new("people")
loader.add("term" =>{ name , email }, "id" => self.id, "data" => {
"link" => Rails.application.routes.url_helpers.person_path(self)
})
end
and
def load_into_soulmate
loader = Soulmate::Loader.new("people")
loader.add("term" =>{ "name" => name ,"email" => email }, "id" => self.id, "data" => {
"link" => Rails.application.routes.url_helpers.person_path(self)
})
end
error show when i use Person.find_each(&:save) for add datas to redis:
ArgumentError: ArgumentError
from /var/lib/gems/2.2.0/gems/soulmate-1.1.0/lib/soulmate/loader.rb:31:in `add'
but all is wrong.
I think you have to use aliases.
def load_into_soulmate
loader = Soulmate::Loader.new("people")
loader.add("term" =>"name", "id" => self.id, "aliases" => [email], "data" => {
"link" => Rails.application.routes.url_helpers.person_path(self)
})
end

Collection is serializing with the each-object key being the pluralized key, cannot figure out why

We've got a simple api endpoint that works like so:
def index
render json: Country.all
end
This is unfortunately giving us this output:
{
"countries" => [
[0] {
"countries" => {
"id" => 1,
"iso" => "US",
"iso3" => "USA",
"iso_name" => "UNITED STATES",
"name" => "United States of Foo",
"numcode" => 840
}
},
[1] {
"countries" => {
"id" => 2,
"iso" => "CA",
"iso3" => "CAN",
"iso_name" => "CANADA",
"name" => "Canada",
"numcode" => 124
}
}
]
}
Notice that the key for each individual object is the plural form of the key.
However, when we set the endpoint to work like so
def inded
render json: {countries: Country.all}
end
The output looks like so:
{
"countries" => [
[0] {
"country" => {
"id" => 1,
"iso" => "US",
"iso3" => "USA",
"iso_name" => "UNITED STATES",
"name" => "United States of Foo",
"numcode" => 840
}
},
[1] {
"country" => {
"id" => 2,
"iso" => "CA",
"iso3" => "CAN",
"iso_name" => "CANADA",
"name" => "Canada",
"numcode" => 124
}
}
]
}
I.e., correct.
However, setting the key like {countries: Country.all} is bad form, and I'd like to understand why rails is serializing each element with the collection key rather than the object key (that is, why it's plural and not singular for each country).
We have not overridden to_json or any other serialization methods. We are using the default rails model serializer (I tried making an explicit serializer, but there was no change in behavior). I cannot, for the life of me, figure out why it is pluralizing these keys.
Edit: There is even more weirdness. I was incorrect about the explicit serializer, when I set up a serializer (with just the attributes as it normally displays), I get this:
{
"countries" => [
[0] {
"id" => 1,
"iso" => "US",
"iso3" => "USA",
"iso_name" => "UNITED STATES",
"name" => "United States of Foo",
"numcode" => 840
},
[1] {
"countries" => {
"id" => 2,
"iso" => "CA",
"iso3" => "CAN",
"iso_name" => "CANADA",
"name" => "Canada",
"numcode" => 124
}
}
]
}
The first object has no key, and every other one is plural. I tested both in tests, and confirmed by making the actual API call.
I can't find anything that would override this other than an overridden <=> and to_s. These should not affect output in this way?
Mike, I think you copied and pasted something wrong, or you might just be confused.
Both outputs have the same results: Countries (Plural) as the main response, and country(Singular) for each individual inside countries. Or am I misreading?
I think what's happening here is that you're trying to specify the root key in a way that AM::S doesn't support.
Instead of render json: { countries: Country.all }, I'd recommend trying render json: Country.all, root: "countries" (specifying the root key is unnecessary if you're calling the serializer from within CountriesController, otherwise you need it to get the functionality you desire).
See https://github.com/rails-api/active_model_serializers/tree/0-8-stable#arrays for more information.

Resources