Reputation: 55293
I have a Tag model:
class Tag < ActiveRecord::Base
has_many :taggings, :dependent => :destroy
has_many :posts, :through => :taggings
has_many :subscriptions
has_many :subscribed_users, :source => :user, :through => :subscriptions
end
and a Post model:
class Post < ActiveRecord::Base
attr_accessible :title, :content, :tag_names
belongs_to :user
has_many :taggings, :dependent => :destroy
has_many :tags, :through => :taggings
attr_writer :tag_names
after_save :assign_tags
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
private
def assign_tags
return if @tag_names.blank?
@tag_names.split(" ").each do |name|
tag = Tag.find_or_create_by_name(name)
self.tags << tag unless tags.include?(tag)
end
end
end
The assign_tags
method stores the saved tags in :tag_names
and displays it in an input field in this fashion: tag1 tag2 tag3
(values are separated by spaces).
views/posts/_form.html.erb:
<div class="field">
<%= f.label :tag_names %><br />
<%= f.autocomplete_field :tag_names, autocomplete_tag_name_posts_path, :"data-delimiter" => ' '%>
</div>
As you can see, assign_tags
, enables me to add/push tags to tag_names
. But if I delete a tag from the input field and save. The tag will still show up.
Any suggestions to help me solve this issue?
(Maybe tag_names
should just empty itself before the tags are pushed in. But no idea how to code that).
Upvotes: 0
Views: 44
Reputation:
Before assigning tags, you'll want to clear the tags for that item. e.g.
def assign_tags
self.tags = []
return if @tag_names.blank?
@tag_names.split(" ").each do |name|
tag = Tag.find_or_create_by_name(name)
self.tags << tag unless tags.include?(tag)
end
end
Update:
Or, a method that will hit the database a bit less:
def assign_tags
ntags = []
@tag_names.to_s.split(" ").each do |name|
ntags << Tag.find_or_create_by_name(name)
end
self.tags = ntags
end
If you wanted to get really crazy with the write-less-do-more paradigm, you could do:
def assign_tags
self.tags = @tag_names.to_s.split(" ").inject([]) do |arr, name|
arr << Tag.find_or_create_by_name(name)
arr
end
end
Alternatively, I'd recommend looking into the acts-as-taggable-on gem.
Upvotes: 1