Creating URLs for tags with act_as_taggable_on

I would like to create url bullets for tags controlled by act_as_taggable_on shortcut. For example, instead of URLs like http://myapp.com/tags/5 , I would like to have http://myapp.com/tags/my-tag (where "my tag" is the unique name of the tag) .

In models that I create myself, I usually do this by overriding the to_param model method and creating a โ€œslugโ€ field in the model to save the result of the new to_param method. I tried to do this using the Tag ActsAsTaggableOn model, but it does not work.

Otherwise, I can override things in the tag.rb class ActsAsTaggableOn as follows:

# Overwrite tag class ActsAsTaggableOn::Tag.class_eval do def name n = read_attribute(:name).split n.each {|word| word.capitalize!}.join(" ") end end 

However, if I try to override the to_param method in the same block with the method definition, for example:

 def to_param name.parameterize end 

Rails still generates and responds to routes with integer identifiers, not with a parameterized name. Actually in the console, if I try something like

 ActsAsTaggableOn::Tag.find(1).to_param 

An integer identifier is returned, not the result of an overridden to_param method.

I would prefer not to fork the gem and tune it if I can do this with my own application code. Thanks.

+8
ruby-on-rails acts-as-taggable-on
source share
5 answers

I use the friendly_id gem ( https://github.com/norman/friendly_id ) to control the slugs. My bullet method for my tags is similar to yours, but a little easier.

I just created an act_as_taggable_on.rb initializer with the following code:

 # act_as_taggable_on.rb ActsAsTaggableOn::Tag.class_eval do has_friendly_id :name, :use_slug => true, :approximate_ascii => true, :reserved_words => ['show', 'edit', 'create', 'update', 'destroy'] end 

And then:

 @user = User.new :name => "Jamie Forrest" @user.tag_list = "This is awesome!, I'm a ruby programmer" @user.save 

And voilรก:

 ActsAsTaggableOn::Tag.find('this-is-awesome') #=> #<Tag id: 1, name: "This is awesome!"> ActsAsTaggableOn::Tag.find('im-a-ruby-programmer') #=> #<Tag id: 2, name: "I'm a ruby programmer"> 

Hope this help ...

+13
source share

@vitork is a good start, but it does not work for newer versions of friendly_id and act_as_taggable. Here's the updated initializer:

 ActsAsTaggableOn::Tag.class_eval do extend FriendlyId friendly_id :name, :use => :slugged, :slug_column => :permalink, :reserved_words => ['show', 'edit', 'create', 'update', 'destroy'] end 

My db column is called permalink, you can use slugged if you want. By the way, I use the following:

  • friendly_id (4.0.5)
  • act-as-taggable-on (2.2.2)

Thanks Vitork for the source code!

+14
source share

Actually the answer is much simpler and you do not need to use friendly_id or any other unnecessary extension.

config / Initializers / act_as_taggable_on.rb

 ActsAsTaggableOn::Tag.class_eval do before_save { |tag| tag.slug = name.parameterize if name_changed? } def to_param slug end end 

Add a slug column if you need, otherwise skip the before_save callback.

Then in the view instead of repeating as

 article.tag_list.each do |tag|.. 

you will also be sorting

 article.tags.each 

because tag_list gives you only strings, while with tags you have real instances of tags. And at least in the controller

 if params[:tag] tag = ActsAsTaggableOn::Tag.find_by_slug(params[:tag]) @articles = Article.moderated.includes(:user).tagged_with(tag) end 
+9
source share

To make this work with the latest version (Rails 4.x, friendly_id 5.x), follow these steps:

Create a transition to add a slug to tags table

 # rails generate migration add_slugs_to_tags class AddSlugToTags < ActiveRecord::Migration def change add_column :tags, :slug, :string add_index :tags, :slug end end 

You can rename a column: slug - you must specify the column name in the initializer if you change it. Remember to start the rake db:migrate migration.

Create an Initializer for ActsAsTaggableOn

 # config/initializers/acts_as_taggable_on.rb ActsAsTaggableOn::Tag.class_eval do extend FriendlyId friendly_id :name, use: :slugged end 

When searching for tags, you should use ActsAsTaggableOn::Tag.friendly.find 'tag-name' or add :finders to friendly_id: use the call to use find directly in the model. Read the friendly_id guides for more information.

+7
source share

There is another way.

Create a controller for tags with one action:

 rails g controller tags index 

In routes.rb, change the generated route to:

 get 'tags/:tag' => 'tags#index', as: :tag 

In tags_controller.rb add this code:

 def index @tag = params[:tag] @entries = Entry.tagged_with(@tag) end 

where Entry is the name of the model.

Now you can get all posts with good urls like example.com/tags/animals


Usage in Views:

 - @entry.tags.each do |tag| = link_to tag, tag_path(tag.name) 
0
source share

All Articles