#167 More on Virtual Attributes
Use a virtual attribute to implement a simple tagging feature. In this episode I show you how to assign virtual attributes through a callback instead of a setter method.
- Download:
- source codeProject Files in Zip (98 KB)
- mp4Full Size H.264 Video (9.92 MB)
- m4vSmaller H.264 Video (7.29 MB)
- webmFull Size VP8 Video (19.1 MB)
- ogvFull Size Theora Video (13.7 MB)
Resources
bash
script/generate model tag name:string
script/generate model tagging article_id:integer tag_id:integer
rake db:migrate
script/generate model tag name:string script/generate model tagging article_id:integer tag_id:integer rake db:migrate
models/tagging.rb
class Tagging < ActiveRecord::Base
belongs_to :article
belongs_to :tag
end
class Tagging < ActiveRecord::Base belongs_to :article belongs_to :tag end
models/tag.rb
class Tag < ActiveRecord::Base
has_many :taggings, :dependent => :destroy
has_many :articles, :through => :taggings
end
class Tag < ActiveRecord::Base has_many :taggings, :dependent => :destroy has_many :articles, :through => :taggings end
models/article.rb
class Article < ActiveRecord::Base
has_many :comments, :dependent => :destroy
has_many :taggings, :dependent => :destroy
has_many :tags, :through => :taggings
validates_presence_of :name, :content
attr_writer :tag_names
after_save :assign_tags
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
private
def assign_tags
if @tag_names
self.tags = @tag_names.split(/\s+/).map do |name|
Tag.find_or_create_by_name(name)
end
end
end
end
class Article < ActiveRecord::Base has_many :comments, :dependent => :destroy has_many :taggings, :dependent => :destroy has_many :tags, :through => :taggings validates_presence_of :name, :content attr_writer :tag_names after_save :assign_tags def tag_names @tag_names || tags.map(&:name).join(' ') end private def assign_tags if @tag_names self.tags = @tag_names.split(/\s+/).map do |name| Tag.find_or_create_by_name(name) end end end end
articles/_form.html.erb
<p>
<%= f.label :tag_names %><br />
<%= f.text_field :tag_names %>
</p>
<p> <%= f.label :tag_names %><br /> <%= f.text_field :tag_names %> </p>

