Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incomplete index in Callback #5

Closed
samqiu opened this issue Jan 30, 2014 · 12 comments
Closed

Incomplete index in Callback #5

samqiu opened this issue Jan 30, 2014 · 12 comments

Comments

@samqiu
Copy link

samqiu commented Jan 30, 2014

Hi @karmi ,

Thank you for your awesome gems!

I am replacing Tire to elasticsearch-rails, the first issue is that it won't perform as_indexed_json when update_document, It' s update changed_attributes only.

Is there any solution about this? perform as_indexed_json when update_document, not only changed_attributes .

Source

https://github.com/elasticsearch/elasticsearch-rails/blob/master/elasticsearch-model/lib/elasticsearch/model/indexing.rb#L334

Model

class User << ActiveRecord::Base

  has_many :keywords

  def as_indexed_json(options={})
    { :id => id, 
      email: email,
      first_name: first_name, 
      last_name: last_name,

      full_name: "#{first_name} #{last_name}",
      research_interests: keywords.map(&:name)
    }
  end

end
@karmi
Copy link
Contributor

karmi commented Jan 30, 2014

Hi, thanks! Can you clarify the issue a bit, please?

The thing is, that -- contrary to Tire --, update_document intercepts model changes, via `ActiveModel::Dirty``, and performs a partial update of only changed properties.

So, are you saying that some of these changes are not correctly intercepted? Would it be feasible to model it in the integration test?

@samqiu
Copy link
Author

samqiu commented Jan 30, 2014

Thanks!

elasticsearch-rails is correctly updated the changed attributes.

But some field also need to update. like the full_name below.

class User << ActiveRecord::Base

  def as_indexed_json(options={})
    { :id => id,  
      first_name: first_name, 
      last_name: last_name,
      full_name: "#{first_name} #{last_name}", 
    }
  end

end

So, to avoid more problems, I think is better invoke as_indexed_json when perform update_document, not just update the changed_attributes.

Hope you can understand my poor English.

@karmi
Copy link
Contributor

karmi commented Jan 30, 2014

... full_name: "#{first_name} #{last_name}", ...

Aaah, now I know what you mean -- full_name is defined only in as_indexed json, so it is not intercepted in changed attributes...

I think is better invoke as_indexed_json when perform update_document, not just updated the changed_attributes

Yeah, but that would defeat the purpose of the partial update I guess :) I'll have to revisit this part...

@samqiu
Copy link
Author

samqiu commented Jan 30, 2014

Exactly!

But I think the partial update should be based on as_indexed_json.

@samqiu samqiu closed this as completed Jan 30, 2014
@karmi
Copy link
Contributor

karmi commented Jan 31, 2014

But I think the partial update should be based on as_indexed_json

Unless I'm mistaken, that wouldn't help, since the full_author method wouldn't appear in the changed attributes. And if we would simply call as_indexed_json, then we're sending the full model serialization over the wire, defeating the purpose of the partial update?

@samqiu
Copy link
Author

samqiu commented Feb 4, 2014

Thanks,

Temporary using this to fix it :

after_update -> {
  __elasticsearch__.index_document
}

@samqiu
Copy link
Author

samqiu commented Feb 4, 2014

Should I reopen this issue for tracking?

@karmi
Copy link
Contributor

karmi commented Feb 4, 2014

I still haven't found a way how to solve this acceptably, please see my comments above.

Unless there some kind of support for "computed" or "dependent" model attributes (a la e.g. Ember.js), these derived attributes simply are not reachable by ActiveModel::Dirty.

I can see an argument that as soon as you define as_indexed_json on your model, the callback should automatically call index_document. On the other hand, I wouldn't like making the automatic callbacks so magical and smart, they handle every use case... I've seen much of these issues and participated in many discussions like this in Tire, and unless there's a clear way, it's usually best leaving this to the user?

@karmi
Copy link
Contributor

karmi commented Feb 15, 2014

So, for the record, the trouble with your use case is that full_name is constructed on the fly, during as_indexed_json call. In this case, you simply have to take indexing in your own hands.

If it were a "read-only", or "computed" attribute, such as:

class Person < ActiveRecord::Base
  def full_name
    [first_name, last_name].compact.join(' ')
  end
end

which would be used in as_indexed_json, then you'd have to redefine first_name and last_name accessors to call attribute_will_change!. There's a nice StackOverflow discussion: Track dirty for not-persisted attribute in an ActiveRecord object in Rails about a similar use case.

So, in my opinion, the library behaves absolutely predictably here.

@samqiu
Copy link
Author

samqiu commented Feb 18, 2014

@karmi

Now I know what to do, thank you!

karmi added a commit that referenced this issue Apr 15, 2014
…serialized during update

Previously, the `update_document` method simply intercepted the changes to the model, via the
`@__changed_attributes` variable, and used these directly.

This caused models with a custom serialization method to be incorrectly serialized, namely
unwanted attributes were added.

This patch looks for `as_indexed_json` defined on the model, and when it finds it,
filters the changed attributes through the keys.

Closes #75

Related:

* #59
* #57
* #52
* #40
* #37
* #5
@karmi
Copy link
Contributor

karmi commented Apr 15, 2014

@samqiu Please see the linked commit, it should solve one variant of the bug you have hit. I'm afraid, though, that your specific case, ie. having a custom method, which is then used in the as_indexed_json, simply requires defining the callbacks on your own.

Let me repeat once more that the "automatic callbacks" were always meant as a convenience -- for most complex cases, you need to define them, preferably via Sidekiq/etc...

@samqiu
Copy link
Author

samqiu commented Apr 16, 2014

Thank you. I will going to use Sidekiq for indexing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants