-
Notifications
You must be signed in to change notification settings - Fork 11
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
5441 – Change how we create imported fact-checks when an item already exists #2079
5441 – Change how we create imported fact-checks when an item already exists #2079
Conversation
@caiosba when you have some time, could you please take a look into the tests?
|
} | ||
GRAPHQL | ||
|
||
post :create, params: { query: query, team: t.slug } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest we put a assert_no_difference 'ProjectMedia.count'
and a assert_difference 'FactCheck.count'
around this line.
Great start @vasconsaurus , that's exactly what we intended - I added a couple of suggestions to only one of the tests but they actually apply to both. It's just a couple of |
@vasconsaurus my suggestion to start is to Idea: Wrap the
# FIXME: Refactor this as an around_save that GraphQL types can define themselves
begin
self.safe_save(obj, attrs, parents_mapping.keys) # OR if idea (2) above: obj.save_with_version!
rescue StandardError => e # I know it's not StandardError, let's rescue the exception we currently get... we can replace the current exception class by a specific one if it makes things easier
if obj.is_a?(ProjectMedia) && !obj.set_fact_check.blank? && !obj.set_original_claim.blank?
obj = obj.handle_fact_check_for_existing_claim # We can then define this method in the ProjectMedia model and implement the logic for the two cases we listed in the ticket - it will be much easier to unit-test too
else
raise e
end
end Let me know if it makes sense! :) But a question before you proceed: Were you able to reproduce in the two automated tests the same error we get from Zapier? Would be good to document it (e.g., the test run and the output) in the ticket. |
@vasconsaurus I do not have any special considerations that we need to take regarding |
@caiosba I think I'll be able to get back to this one today, and will look into:
|
@caiosba it seems we do get the exact same error 🎉 From Zapier logs:
From our tests
|
That's perfect, Manu! 👌 |
908c461
to
7dc8545
Compare
@caiosba @jayjay-w I added new tests here |
@vasconsaurus yes, that's expected. We have a filter for existing items for media submissions that happen through tiplines:
I suggest you ignore it for now, and we can work on that in a separate, follow-up ticket. I added that to the ticket so we don't forget about it - let's revisit at the end. |
self.safe_save(obj, attrs, parents_mapping.keys) | ||
begin | ||
self.safe_save(obj, attrs, parents_mapping.keys) | ||
rescue StandardError => e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remember to replace this by a more specific exception.
app/models/project_media.rb
Outdated
@@ -430,6 +430,22 @@ def apply_rules_and_actions_on_update | |||
self.team.apply_rules_and_actions(self, rule_ids) | |||
end | |||
|
|||
def handle_fact_check_for_existing_claim | |||
# find the project media with the original claim media | |||
pm = ProjectMedia.find_by(media_id: self.media_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please filter by the team_id
as well.
self.safe_save(obj, attrs, parents_mapping.keys) | ||
rescue StandardError => e | ||
if obj.is_a?(ProjectMedia) && obj.set_fact_check.present? && obj.set_original_claim.present? | ||
obj = obj.handle_fact_check_for_existing_claim |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per our conversation, let's turn this method into a class method:
obj = ProjectMedia.handle_fact_check_for_existing_claim(obj)
app/models/project_media.rb
Outdated
@@ -430,6 +430,22 @@ def apply_rules_and_actions_on_update | |||
self.team.apply_rules_and_actions(self, rule_ids) | |||
end | |||
|
|||
def handle_fact_check_for_existing_claim |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per comment above, turn this into a class method.
app/models/project_media.rb
Outdated
self.set_original_claim = nil | ||
self.media_id = m.id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once this becomes a class method, we can create a new instance here:
pm = obj.clone # If it doesn't work as expected, replace this by ProjectMedia.new
pm.set_original_claim = nil
pm.media_id = m.id
pm.save!
@caiosba I have questions! I think I might be missing something
I'm sure I'm missing a lot of things about how this part of the code works. What should I be returning from the rescue? What am I missing here? And one last question: |
@vasconsaurus hummm... please push what you have so I can take a look :)
For that, you should just test the |
7dc8545
to
d9dca69
Compare
so we are able to send an url
This shouldn't be StandardError, but will keep it for now.
If the item already has a fact-check in a different language Currently broken
add unit tests to reflect current behavior
for this to work I had to change create_claim_description_and_fact_check to be public
The changes I added to sample_data had come side effects to other tests. So I'm rolling that back, and updated the two graphql tests to not need those changes anymore.
9771c6d
to
8b364f0
Compare
The error can be slightly different, parsing the way we were before doesn't work for every error. This caused test test/controllers/graphql_controller_12_test.rb:69, GraphqlController12Test#test_should_not_create_feed_invitation, to break.
@caiosba I finished the changes we talked about, could you take a look and see if this is ready for review or if there is something missing? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great @vasconsaurus , glad that the approach we discussed has worked as expected! I left a few comments, but the approach is correct. Did the tests pass?
begin | ||
obj.save_with_version! | ||
rescue RuntimeError => e | ||
if e.message.include?("This item already exists") && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Request: @vasconsaurus , this is not a good way to check for the error because of two reasons:
(1) If I18n.locale
is not English, then this error message will be localized, so won't match this condition (for example, for Portuguese it will be "Este item já existe").
(2) The copy for the error message may change in the future.
I suggest you check for the exception class or some other non-localized information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@caiosba, questions:
- The error we get is a
RuntimeError
, so it's not super specific. It does send the lapis code in the message, so I changed it to look for that. (here) - However, would it be worth for us to create a custom error? We get the error from here:
check-api/app/models/concerns/project_association.rb
Lines 139 to 155 in cb97946
def is_unique obj_name = 'media' obj = ProjectMedia.where(team_id: self.team_id, media_id: self.media_id).last unless obj.nil? error = { message: I18n.t("#{obj_name}_exists", team_id: obj.team_id, id: obj.id), code: LapisConstants::ErrorCodes::const_get('DUPLICATED'), data: { team_id: obj.team_id, type: obj_name, id: obj.id, url: obj.full_url } } raise error.to_json end end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vasconsaurus , I don't think we need a specific code, I think that DUPLICATED
is good enough for this case. But please use the variable LapisConstants::ErrorCodes::const_get('DUPLICATED')
instead of the hard-coded value "9".
app/models/project_media.rb
Outdated
@@ -430,6 +430,31 @@ def apply_rules_and_actions_on_update | |||
self.team.apply_rules_and_actions(self, rule_ids) | |||
end | |||
|
|||
def self.handle_fact_check_for_existing_claim(existing_pm,new_pm) | |||
if existing_pm.fact_check.blank? | |||
existing_pm.appended_fact_check_from(new_pm) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Since this method takes an action, I suggest to name it with the verb name in imperative form, so, append_fact_check_from
.
app/models/project_media.rb
Outdated
existing_pm.appended_fact_check_from(new_pm) | ||
elsif existing_pm.fact_check.present? | ||
if existing_pm.fact_check.language != new_pm.set_fact_check['language'] | ||
new_pm.replaced_with_blank_media |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Since this method takes an action, I suggest to name it with the verb name in imperative form, so, replace_with_blank_media
.
Yes 🎉 |
Since this method takes an action, I suggest to name it with the verb name in imperative form
(1) If I18n.locale is not English, then this error message will be localized, so won't match this condition (for example, for Portuguese it will be "Este item já existe"). (2) The copy for the error message may change in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work @vasconsaurus ! Thanks for addressing the comments from the previous reviews. I added a couple of suggestions mostly for clarity.
begin | ||
obj.save_with_version! | ||
rescue RuntimeError => e | ||
if e.message.include?("\"code\":#{LapisConstants::ErrorCodes::const_get('DUPLICATED')}") && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could also do a JSON.parse
on the message and check for the code, but this is fine too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried this before, but we ran into an issue with test GraphqlController12Test#test_should_not_create_feed_invitation
/ rails test test/controllers/graphql_controller_12_test.rb:69
.
[11, 20] in /app/app/graph/mutations/graphql_crud_operations.rb
11: begin
12: obj.save_with_version!
13: rescue RuntimeError => e
14: require 'byebug'
15: byebug
=> 16: if e.message.include?("\"code\":#{LapisConstants::ErrorCodes::const_get('DUPLICATED')}") &&
17: obj.is_a?(ProjectMedia) &&
18: obj.set_fact_check.present? &&
19: obj.set_original_claim.present?
20: existing_pm = ProjectMedia.find(JSON.parse(e.message)['data']['id'])
(byebug) e
#<RuntimeError: No permission to create FeedInvitation>
(byebug) JSON.parse(e)
*** TypeError Exception: no implicit conversion of RuntimeError into String
nil
(byebug) JSON.parse(e.message)
*** JSON::ParserError Exception: unexpected token at 'No permission to create FeedInvitation'
nil
obj.is_a?(ProjectMedia) && | ||
obj.set_fact_check.present? && | ||
obj.set_original_claim.present? | ||
existing_pm = ProjectMedia.find(JSON.parse(e.message)['data']['id']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to my other comment: this JSON.parse
could be at the top and then the parsed data
object could be used to check for the id
here and for the error code at the top.
app/models/project_media.rb
Outdated
def self.handle_fact_check_for_existing_claim(existing_pm,new_pm) | ||
if existing_pm.fact_check.blank? | ||
existing_pm.append_fact_check_from(new_pm) | ||
elsif existing_pm.fact_check.present? | ||
if existing_pm.fact_check.language != new_pm.set_fact_check['language'] | ||
new_pm.replace_with_blank_media | ||
end | ||
end | ||
end | ||
|
||
def append_fact_check_from(new_pm) | ||
self.set_claim_description = new_pm.set_claim_description | ||
self.set_fact_check = new_pm.set_fact_check | ||
self.create_claim_description_and_fact_check | ||
self | ||
end | ||
|
||
def replace_with_blank_media | ||
m = Blank.create! | ||
self.set_original_claim = nil | ||
self.media_id = m.id | ||
self.save! | ||
self | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion for this whole block... I think it's more clear to:
- Explicitly say, after line 435, that we're returning the existing item:
return existing_pm
- Explicitly say, after line 438, that we're returning the new item:
return new_pm
And then in the methods append_fact_check_from
and replace_with_blank_media
, you don't need to return self
in their last lines (447 and 455).
Description
Wanted Behavior
ProjectMedia
Context
Importing a fact-check with a link original claim will fail when a project media with that link media already exists.
When importing, we create a project media to create the fact-check. If that project media has an original claim, we create a media as well. If the original claim is a link, we try to create a link media.
Since duplicate link medias are not permitted, if a link media with this link already exists, trying to create this new media from the same link will fail. Then creating the project media and fact-check will fail as well.
The issue with this
We will have the project media with the link media, but will fail to create the fact-check for it, even though the partner has one. If the partner has a fact-check, we want to be able to attach it to the correct existing project media.
A related issue
Sometimes a partner might have a fact-check for a project media, but if they have many languages, they might want to have more than one fact-check associated with that project media. Since this is currently not possible: if they have a fact-check in a different language, we want to create the fact-check associated to a blank media, instead of the link media.
References: CV2-5441
How has this been tested?
Things to pay attention to during code review
Please describe parts of the change that require extra attention during code review, for example:
Checklist