Создание слагов URL для тегов с act_as_taggable_on

Я хотел бы создать слаги URL-адресов для тегов, управляемых драгоценным камнем acts_as_taggable_on. Например, вместо таких URL, как http://myapp.com/tags/5, я хотел бы иметь http://myapp.com/tags/my-tag (где "мой тег" — это уникальное имя тега).

В моделях, которые я создаю сам, я обычно делаю это, переопределяя метод модели to_param и создавая поле «slug» в модели для сохранения результата нового метода to_param. Я попытался сделать это с моделью тегов ActsAsTaggableOn, но это не работает.

В противном случае я могу переопределить вещи в классе tag.rb ActsAsTaggableOn следующим образом:

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

Однако, если я попытаюсь переопределить метод to_param в том же блоке с определением метода, например:

def to_param
  name.parameterize
end

Rails по-прежнему генерирует и отвечает на маршруты с целочисленными идентификаторами, а не с параметризованным именем. На самом деле в консоли, если я попробую что-то вроде

ActsAsTaggableOn::Tag.find(1).to_param

Возвращается целочисленный идентификатор, а не результат переопределенного метода to_param.

Я бы предпочел не разветвлять драгоценный камень и не настраивать его, если есть способ сделать это с помощью моего собственного кода приложения. Спасибо.


person Jamie Forrest    schedule 13.02.2011    source источник


Ответы (5)


Я использую гем friendly_id ( https://github.com/norman/friendly_id ) для управления слагами. . Мой метод создания слагов для тегов похож на ваш, но немного проще.

Я только что создал инициализатор act_as_taggable_on.rb со следующим кодом:

# 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

А потом:

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

И вуаля:

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">

Надеюсь, эта помощь...

person Vitor Arimitsu    schedule 13.05.2011

Код @vitork — хорошее начало, но он не работает для более новых версий friendly_id и act_as_taggable. Вот обновленный инициализатор:

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

Мой столбец БД называется permalink, вы можете использовать slugged, если хотите. Кстати, я использую следующее:

  • дружественный_id (4.0.5)
  • действует как помечаемый (2.2.2)

Спасибо Vitork за исходный код!

person johnkoht    schedule 14.05.2012

На самом деле ответ намного проще, и вам не нужно использовать friendly_id или любое другое ненужное расширение.

с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

Добавьте столбец slug, если вам нужно, в противном случае пропустите обратный вызов before_save.

Затем в представлении вместо повторения, как

article.tag_list.each do |tag|..

вы будете повторять так

article.tags.each

потому что tag_list дает вам только строки, тогда как с тегами у вас есть настоящие экземпляры тегов. И хотя бы в контроллере

if params[:tag]
   tag = ActsAsTaggableOn::Tag.find_by_slug(params[:tag])
   @articles = Article.moderated.includes(:user).tagged_with(tag)
end
person valachi    schedule 19.10.2012
comment
Блестящий. Именно то, что я искал - person DaniG2k; 05.10.2015
comment
Это работает даже для Rails 5 и act_as_taggable_on v4. - person Nikhil; 07.11.2016

Чтобы это работало с последней версией (Rails 4.x, friendly_id 5.x), выполните следующие действия:

Создайте миграцию, чтобы добавить слаг в таблицу тегов

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

Вы можете переименовать столбец :slug — вы должны указать имя столбца в инициализаторе, если вы его меняете. Не забудьте запустить миграцию rake db:migrate.

Создайте инициализатор для ActsAsTaggableOn.

# config/initializers/acts_as_taggable_on.rb
ActsAsTaggableOn::Tag.class_eval do
  extend FriendlyId

  friendly_id :name, use: :slugged
end

При поиске тегов вы должны использовать ActsAsTaggableOn::Tag.friendly.find 'tag-name' или добавить :finders к friendly_id: используйте вызов, чтобы использовать поиск непосредственно на модели. Подробнее читайте в руководствах по дружественному_id.

person Lenart    schedule 13.04.2014

Есть еще один способ.

Создайте контроллер для тегов одним действием:

rails g controller tags index

В routes.rb измените сгенерированный маршрут на:

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

В tags_controller.rb добавьте этот код:

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

где Entry — название модели.

Теперь вы можете получить все записи с красивыми URL-адресами, такими как example.com/tags/animals.


Использование в представлениях:

- @entry.tags.each do |tag|
  = link_to tag, tag_path(tag.name)
person user1201917    schedule 10.11.2016