Вы можете использовать метод tag_ids
в экземпляре Post
.
В вашем контроллере создайте хэш тега.Еще лучше кэшировать тэг хеша.
Добавьте это к вашему application_controller.rb
.
def all_tags
@all_tags ||=Rails.cache.fetch('Tag.all', :expire_in => 15.minutes)){ Tag.all }
# without caching
#@all_tags ||= Tag.all
end
def all_tags_hash
@all_tags_hash ||= all_tags.inject({}){|hash, tag| hash[tag.id]=tag;hash}
end
def all_tags_by_ids ids
ids ||= []
ids = ids.split(",").map{|str| str.to_i} if ids.is_a?(string)
all_tags_hash.values_at(*ids)
end
helper_method :all_tags, :all_tags_hash, :all_tags_by_id
Теперь ваше частичное можно переписать как
# posts/_item.html.haml
- all_tags_by_ids(post.tag_ids).each do |tag|
%li
%a{:href => "/tags/#{tag.name}"}= tag.name.titleize
Мое решение кешируетTag
моделей за 15 минут.Убедитесь, что вы добавили наблюдателя / фильтр в модель тега, чтобы сделать недействительным / обновить кэш во время создания / обновления / удаления.
В вашем config\environment.rb
config.active_record.observers = :tag_observer
Добавьте файл tag_observer.rb
в каталог app\models
.
class TagObserver < ActiveRecord::Observer
def after_save(tag)
update_tags_cache(tag)
end
def after_destroy(tag)
update_tags_cache(tag, false)
end
def update_tags_cache(tag, update=true)
tags = Rails.cache.fetch('Tag.all') || []
tags.delete_if{|t| t.id == tag.id}
tags << tag if update
Rails.cache.write('Tag.all', tags, :expire_in => 15.minutes)
end
end
Примечание. То же решение будет работать безтакже кеш.
Это решение все еще требует от вас запроса к таблице tags
для идентификаторов Tag
.Дальнейшую оптимизацию можно выполнить, сохранив идентификаторы тегов в виде строки с разделителями-запятыми в модели Post
(не считая ее сохранение в таблице post_tags
).
class Post < ActiveRecord::Base
has_many :post_tags
has_many :tags, :through => :post_tags
# add a new string column called tag_ids_str to the `posts` table.
end
class PostTag < ActiveRecord::Base
belongs_to :post
belongs_to :tag
after_save :update_tag_ids_str
after_destroy :update_tag_ids_str
def update_tag_ids_str
post.tag_ids_str = post.tag_ids.join(",")
post.save
end
end
class Tag < ActiveRecord::Base
has_many :post_tags
has_many :posts, :through => :post_tags
end
Теперь ваш фрагмент можно переписать как
# posts/_item.html.haml
- all_tags_by_ids(post.tag_ids_str).each do |tag|
%li
%a{:href => "/tags/#{tag.name}"}= tag.name.titleize