Updating tag saving logic to never save duplicates

This commit is contained in:
Hannah Wolfe 2013-09-13 21:38:53 +01:00
parent 003f9d2048
commit 420986de62

View File

@ -9,6 +9,7 @@ var Post,
converter = new Showdown.converter({extensions: [github]}), converter = new Showdown.converter({extensions: [github]}),
User = require('./user').User, User = require('./user').User,
Tag = require('./tag').Tag, Tag = require('./tag').Tag,
Tags = require('./tag').Tags,
GhostBookshelf = require('./base'); GhostBookshelf = require('./base');
Post = GhostBookshelf.Model.extend({ Post = GhostBookshelf.Model.extend({
@ -141,13 +142,8 @@ Post = GhostBookshelf.Model.extend({
}, },
updateTags: function (newTags) { updateTags: function (newTags) {
var self = this, var self = this;
tagOperations = [],
tagsToDetach,
existingTagIDs,
tagsToCreateAndAdd,
tagsToAddByID,
fetchOperation;
if (newTags === this) { if (newTags === this) {
newTags = this.get('tags'); newTags = this.get('tags');
@ -157,52 +153,57 @@ Post = GhostBookshelf.Model.extend({
return; return;
} }
fetchOperation = Post.forge({id: this.id}).fetch({withRelated: ['tags']}); return Post.forge({id: this.id}).fetch({withRelated: ['tags']}).then(function (thisPostWithTags) {
return fetchOperation.then(function (thisModelWithTags) { var existingTags = thisPostWithTags.related('tags').toJSON(),
var existingTags = thisModelWithTags.related('tags').models; tagOperations = [],
tagsToDetach = [],
tagsToAttach = [];
tagsToDetach = existingTags.filter(function (existingTag) { // First find any tags which have been removed
var tagStillRemains = newTags.some(function (newTag) { _.each(existingTags, function (existingTag) {
return newTag.id === existingTag.id; if (!_.some(newTags, function (newTag) { return newTag.name === existingTag.name; })) {
}); tagsToDetach.push(existingTag.id);
}
return !tagStillRemains;
}); });
if (tagsToDetach.length > 0) { if (tagsToDetach.length > 0) {
tagOperations.push(self.tags().detach(tagsToDetach)); tagOperations.push(self.tags().detach(tagsToDetach));
} }
// Detect any tags that have been added by ID // Next check if new tags are all exactly the same as what is set on the model
existingTagIDs = existingTags.map(function (existingTag) { _.each(newTags, function (newTag) {
return existingTag.id; if (!_.some(existingTags, function (existingTag) { return newTag.name === existingTag.name; })) {
// newTag isn't on this post yet
tagsToAttach.push(newTag);
}
}); });
tagsToAddByID = newTags.filter(function (newTag) { if (tagsToAttach) {
return existingTagIDs.indexOf(newTag.id) === -1; return Tags.forge().query('whereIn', 'name', _.pluck(tagsToAttach, 'name')).fetch().then(function (matchingTags) {
}); _.each(matchingTags.toJSON(), function (matchingTag) {
tagOperations.push(self.tags().attach(matchingTag.id));
tagsToAttach = _.reject(tagsToAttach, function (tagToAttach) {
return tagToAttach.name === matchingTag.name;
});
});
if (tagsToAddByID.length > 0) { _.each(tagsToAttach, function (tagToCreateAndAttach) {
tagsToAddByID = _.pluck(tagsToAddByID, 'id'); var createAndAttachOperation = Tag.add({name: tagToCreateAndAttach.name}).then(function (createdTag) {
tagOperations.push(self.tags().attach(tagsToAddByID)); return self.tags().attach(createdTag.id, createdTag.name);
} });
// Detect any tags that have been added, but don't already exist in the database
tagsToCreateAndAdd = newTags.filter(function (newTag) { tagOperations.push(createAndAttachOperation);
return newTag.id === null || newTag.id === undefined; });
});
tagsToCreateAndAdd.forEach(function (tagToCreateAndAdd) { return when.all(tagOperations);
var createAndAddOperation = Tag.add({name: tagToCreateAndAdd.name}).then(function (createdTag) {
return self.tags().attach(createdTag.id);
}); });
}
tagOperations.push(createAndAddOperation);
});
return when.all(tagOperations); return when.all(tagOperations);
}); });
}, },
// Relations // Relations
user: function () { user: function () {
return this.belongsTo(User, 'created_by'); return this.belongsTo(User, 'created_by');