http://hobo.tylerlesmann.com/entries/4-make-a-blog-with-hobo-tagging
In this episode, we’ll add tagging support to our blog. Features of this lesson will be applicable to any many-to-many relationship in Hobo. Before I go any further, at the time of this writing, Hobo does not support has_and_belongs_to_many :models. A many-to-many relationship will only be blessed with the Hobo magic when implemented using has_many :models, :through => :join_model.
We need two tables, one for tags and a join table. We create these with the following commands:
$ script/generate hobo_model_resource tag name:string
$ script/generate hobo_model tag_assignment
Only thing you haven’t seen before is the hobo_model. It’s like hobo_model_resource less the controllers, which a join table doesn’t need. Let’s add the relationship code to the models. Add these lines to their indicated files before the # — Permissions — # line.
app/models/entry.rb
has_many :tags, :through => :tag_assignments, :accessible => true
has_many :tag_assignments, :dependent => :destroy
app/models/tag.rb
# Let's change the ordering while we're in here. It defaults to created_at.
# This will affect how cards are ordered as well as when tags are viewed as
# a whole.
set_default_order "name"
has_many :entries, :through => :tag_assignments
has_many :tag_assignments, :dependent => :destroy
app/models/tag_assignment.rb
belongs_to :entry
belongs_to :tag
Most of this is pure rails, except for the :accessible. This tells Hobo to build tag assignment into the form for Entry. Whenever a user accesses a tag’s show page, Hobo will display any child objects the coder describes. To describe children, we edit the viewhints, which in this case is app/viewhints/tag_hints.rb. Add this line:
children :entries
Time to apply the changes to the database!
$ script/generate hobo_migration
Note that if you’ve been following along to this tutorial, you will need to add tags to the fields of field-list for the Entry form, if you want to see how regular many-to-many relationships work in Hobo. You’ll remember that the form is described in app/views/taglibs/application.dryml. The way Hobo does these relationships is clumsy as you’ll see, for tagging anyway. It would be better for the blogger to just enter a bunch of words and phrases separated by commas. Let’s make it work that way. Add the following line to the list of fields in app/models/entry.rb:
tagstring :string
This will hold the input string for the user. Now there are a few ways to handle the actual assignment of the tags to the blog entry. We could implement it like we did markdown formatting for posts earlier. Since I haven’t shown how to go outside the box in controllers yet, we’ll do it that way. Open app/controllers/entries_controller.rb and add the following lines before the last end.
def assign_tags
params["entry"]["tags"] = params["entry"]["tagstring"].split(',').collect{
|tag|
'@' + Tag.find_or_create_by_name(tag.strip).id.to_s
}
end
def create
assign_tags
hobo_create
end
def update
assign_tags
hobo_update
end
The meat of the changes is in the assign_tags method. Here we take the tagstring field and split it by commas. Then, we create or get a Tag instance for each tag, pull the id, and add @ to the front of the id. All of these ids are put into the tags param where Hobo will look at them later. We add two other methods: create and update. These will override the default Hobo/rails actions. We first call assign_tags to parse the tags. After this we use hobo_create or hobo_update, which invokes the usual Hobo handling.
Make sure you have the tagstring in the fields of the Entry form and apply the changes to the database.
$ script/generate hobo_migration
Look at that! Easy tagging! One last thing. Let’s make the tags a bit more visible by having them appear on the show page and card for Entry. Since we will need the same code in both places, we will make a new DRYML tag. In app/views/taglibs/application.dryml, remove the existing <extend tag="card" for="Entry"/> and add this:
<extend tag="card" for="Entry">
<old-card merge>
<prepend-body:>
<entry-info/>
</prepend-body:>
</old-card>
</extend>
<def tag="entry-info">
<div>
Posted on <view:created-at/>
</div>
<div>
Tags: <view:tags/>
</div>
</def>
Alter app/views/entries/show.dryml to be like this:
<show-page>
<append-content-header:>
<entry-info/>
</append-content-header:>
<field-list: replace>
<view:body_html/>
</field-list:>
</show-page>
In DRYML, tags are includes with a bit of extra magic. For instance, in this entry-info tag, we are using <view:created-at/> and <view:tags/>. Hobo knows how to handle these depending on the context. If used out of context, Hobo gracefully outputs Not Available. To use a tag, we simply use it by name, like <entry-info/>.
Take a look at the results. Hobo made the entry’s tags each link to the tag’s show page. The tags are more visible and users can easily navigate to similarly tagged blog posts.
In this episode, we’ll add tagging support to our blog. Features of this lesson will be applicable to any many-to-many relationship in Hobo. Before I go any further, at the time of this writing, Hobo does not support has_and_belongs_to_many :models. A many-to-many relationship will only be blessed with the Hobo magic when implemented using has_many :models, :through => :join_model.
We need two tables, one for tags and a join table. We create these with the following commands:
$ script/generate hobo_model_resource tag name:string
$ script/generate hobo_model tag_assignment
Only thing you haven’t seen before is the hobo_model. It’s like hobo_model_resource less the controllers, which a join table doesn’t need. Let’s add the relationship code to the models. Add these lines to their indicated files before the # — Permissions — # line.
app/models/entry.rb
has_many :tags, :through => :tag_assignments, :accessible => true
has_many :tag_assignments, :dependent => :destroy
app/models/tag.rb
# Let's change the ordering while we're in here. It defaults to created_at.
# This will affect how cards are ordered as well as when tags are viewed as
# a whole.
set_default_order "name"
has_many :entries, :through => :tag_assignments
has_many :tag_assignments, :dependent => :destroy
app/models/tag_assignment.rb
belongs_to :entry
belongs_to :tag
Most of this is pure rails, except for the :accessible. This tells Hobo to build tag assignment into the form for Entry. Whenever a user accesses a tag’s show page, Hobo will display any child objects the coder describes. To describe children, we edit the viewhints, which in this case is app/viewhints/tag_hints.rb. Add this line:
children :entries
Time to apply the changes to the database!
$ script/generate hobo_migration
Note that if you’ve been following along to this tutorial, you will need to add tags to the fields of field-list for the Entry form, if you want to see how regular many-to-many relationships work in Hobo. You’ll remember that the form is described in app/views/taglibs/application.dryml. The way Hobo does these relationships is clumsy as you’ll see, for tagging anyway. It would be better for the blogger to just enter a bunch of words and phrases separated by commas. Let’s make it work that way. Add the following line to the list of fields in app/models/entry.rb:
tagstring :string
This will hold the input string for the user. Now there are a few ways to handle the actual assignment of the tags to the blog entry. We could implement it like we did markdown formatting for posts earlier. Since I haven’t shown how to go outside the box in controllers yet, we’ll do it that way. Open app/controllers/entries_controller.rb and add the following lines before the last end.
def assign_tags
params["entry"]["tags"] = params["entry"]["tagstring"].split(',').collect{
|tag|
'@' + Tag.find_or_create_by_name(tag.strip).id.to_s
}
end
def create
assign_tags
hobo_create
end
def update
assign_tags
hobo_update
end
The meat of the changes is in the assign_tags method. Here we take the tagstring field and split it by commas. Then, we create or get a Tag instance for each tag, pull the id, and add @ to the front of the id. All of these ids are put into the tags param where Hobo will look at them later. We add two other methods: create and update. These will override the default Hobo/rails actions. We first call assign_tags to parse the tags. After this we use hobo_create or hobo_update, which invokes the usual Hobo handling.
Make sure you have the tagstring in the fields of the Entry form and apply the changes to the database.
$ script/generate hobo_migration
Look at that! Easy tagging! One last thing. Let’s make the tags a bit more visible by having them appear on the show page and card for Entry. Since we will need the same code in both places, we will make a new DRYML tag. In app/views/taglibs/application.dryml, remove the existing <extend tag="card" for="Entry"/> and add this:
<extend tag="card" for="Entry">
<old-card merge>
<prepend-body:>
<entry-info/>
</prepend-body:>
</old-card>
</extend>
<def tag="entry-info">
<div>
Posted on <view:created-at/>
</div>
<div>
Tags: <view:tags/>
</div>
</def>
Alter app/views/entries/show.dryml to be like this:
<show-page>
<append-content-header:>
<entry-info/>
</append-content-header:>
<field-list: replace>
<view:body_html/>
</field-list:>
</show-page>
In DRYML, tags are includes with a bit of extra magic. For instance, in this entry-info tag, we are using <view:created-at/> and <view:tags/>. Hobo knows how to handle these depending on the context. If used out of context, Hobo gracefully outputs Not Available. To use a tag, we simply use it by name, like <entry-info/>.
Take a look at the results. Hobo made the entry’s tags each link to the tag’s show page. The tags are more visible and users can easily navigate to similarly tagged blog posts.