Теги являются своего рода категориями, которые описывают часть информации (контент) и позволяют пользователю снова искать ее. В этом руководстве вы узнаете, как создать простую систему тегов с нуля в Rails.
Это руководство предполагает базовые знания Ruby on Rails. Я постараюсь сделать это простым.
Обычное использование тегов, которое мы все уже знаем, это твиттер для сбора твитов по определенной теме, связанной с тегом (хэш).
инструменты
- Рельсы 4.1.4
- Ruby 2.0.1
- Фонд 5
Начиная
Исходный код этого приложения можно найти в этом хранилище.
Сначала создайте свой проект Rails:
rails new TaggingTut
Затем добавьте драгоценный камень для рельсов фундамента, удалите драгоценный камень turbolinks
. Запустите bundle install
.
Мы будем использовать sqlite, базу данных по умолчанию, используемую Rails
Удалите эту строку из app / assets / javascript / application.js. , так как мы удалили камень с turbolinks
.
//= require turbolinks
Создание тегов
Создайте модель для тегов с одним атрибутом name
:
rails g model tag name:string
Мы будем индексировать атрибут name ( index: true
), чтобы ускорить наш поиск по этим тегам. Я рекомендую этот урок для использования индексов в ассоциациях Rails.
Теги имеют много сообщений, а сообщения могут иметь более одного тега. Таким образом, отношения будут многие-ко-многим . Мы можем представить эту ассоциацию в Rails двумя способами:
-
Во-первых : используйте ассоциацию
has_and_belongs_to_many
. Это создаст таблицу соединения в базе данных, но не будет сгенерированной модели для соединения. Таким образом, вы не сможете добавлять проверки или любые другие атрибуты в объединение. -
Второе : используйте
has_many, through
которого требуется создать модель для таблицы соединения. Этот способ предпочтителен в большинстве случаев, поэтому мы будем его использовать.
Создание моделей «Пост» и «Пометка», а также
rails g model post author:string content:text rails g model tagging post:belongs_to tag:belongs_to
После создания этих моделей запустите rake db:migrate
.
Теперь мы создадим ассоциации между постами и тегами через ActiveRecord следующим образом:
приложение / модели / post.rb
has_many :taggings has_many :tags, through: :taggings
приложение / модели / tag.rb
has_many :taggings has_many :posts, through: :taggings
app / models / tagging.rb будет сгенерирован так:
belongs_to :post belongs_to :tag
Теперь у нас есть соединение между сообщениями и тегами через таблицу объединения тегов.
Теперь нам нужно обработать создание тегов как часть действия post create
. Итак, мы определим метод, чтобы взять все введенные теги, удалить их, а затем записать каждый тег в базу данных.
Модель Post имела два атрибута, author и content , которые также определены в текущей форме. Атрибут для all_tags также будет добавлен к данным формы. В Rails 4 добавьте нужный (виртуальный, в данном случае) атрибут, используя строгие параметры. Виртуальные атрибуты очень просты, в этом случае они определены как методы получения и установки. Функция strip
предназначена для удаления пробелов
приложение / модели / post.rb
def all_tags=(names) self.tags = names.split(",").map do |name| Tag.where(name: name.strip).first_or_create! end end def all_tags self.tags.map(&:name).join(", ") end
Функция all_tags будет настроена для отображения всех тегов, разделенных запятыми.
Перед созданием контроллера и представлений установите Zurb Foundation:
rails g foundation:install
Теперь настройте контроллер и представления для отображения постов, включая все теги. Создайте app / controllers / posts_controller.rb , набрав:
rails g controller posts index create
Задайте строгие параметры следующим образом, включая наш виртуальный атрибут для хранения всех тегов, введенных через представление:
private def post_params params.require(:post).permit(:author, :content, :all_tags) end
Метод permit
создает белый список параметров, которые необходимо передать. Подробнее о сильных параметрах читайте здесь
Давайте создадим форму с текстовым полем для тегов. Мы создадим пост, используя AJAX. Это довольно просто:
приложение / просмотров / сообщений / _new.html.erb
<div class="row text-center"> <%= form_for(Post.new, remote: true) do |f| %> <div class="large-10 large-centered columns"> <%= f.text_field :author, placeholder: "Author name" %> </div> <div class="large-10 large-centered columns"> <%= f.text_area :content, placeholder: "Your post", rows: 5 %> </div> <div class="large-10 large-centered columns"> <%= f.text_field :all_tags, placeholder: "Tags separated with comma" %> </div> <div class="large-10 large-centered columns"> <%= f.submit "Post", class: "button"%> </div> <% end %> </div>
__remote: true__
— это атрибут, который указывает форму, которая будет отправлена через AJAX, а не через обычный механизм отправки браузера.
После создания нашего поста, create
перенаправит на действие index
и просмотрит существующие посты.
приложение / контроллеры / posts_controller.rb
def index @posts = Post.all end
приложение / просмотров / сообщений / index.html.erb
<div class="row"> <div class="large-8 columns"> <%= render partial: "posts/new" %> </div> </div>
Не забудьте разобраться с маршрутами.
конфиг / routes.rb
root 'posts#index' resources :posts, only: [:create]
Добавьте несколько очень простых стилей в представление следующим образом:
Приложение / активы / таблицы стилей / posts.css.scss
.tags-cloud { margin-top: 16px; padding: 14px; } .top-pad { padding: 25px; } .glassy-bg{ box-shadow: 0px 3px 8px -4px rgba(0,0,0,0.15); background: white; border-radius: 4px; padding-bottom: 12px; } .mt{ margin-top: 10px; } .mb{ margin-bottom: 10px; } .pt{ padding-top: 10px; } .pb{ padding-bottom: 10px; }
Запусти rails s
и посмотрим что у нас получится.
К сожалению, нет сообщений! Мы никогда не писали действие create
.
приложение / контроллеры / posts_controller.rb
def create @post = Post.new(post_params) respond_to do |format| if @post.save format.js # Will search for create.js.erb else format.html { render root_path } end end end
Этот фрагмент создает новую публикацию с параметрами, указанными пользователем, проверяя ее действительность и возвращая результат. Поскольку форма отправляется с AJAX, формат ответа — js
.
Теперь нам нужно создать файл create.js.erb для хранения javascript, который будет запускаться после создания поста:
приложение / просмотров / сообщений / create.js.erb
var new_post = $("<%= escape_javascript(render(partial: @post))%>").hide(); $('#posts').prepend(new_post); $('#post_<%= @post.id %>').fadeIn('slow'); $('#new_post')[0].reset();
Этот код частично отображает вновь созданное сообщение, функция prepend
позволяет отображать его поверх старых сообщений с эффектом fadeIn
.
Создайте партиал, который будет отображать каждое сообщение:
приложение / просмотров / сообщений / _post.html.erb
<%= div_for post do %> <div class="large-12 columns border border-box glassy-bg mt pt"> <strong><%= h(post.author) %></strong><br /> <sup class="text-muted">From <%= time_ago_in_words(post.created_at)%></sup><br /> <div class="mb pb"> <%= h(post.content) %> </div> <div class="tags"> <%=raw post.all_tags %> </div> </div> <% end %>
Прежде чем мы проверяем вывод, изменим представление index
чтобы оно содержало частичное для сообщений:
приложение / просмотров / index.html.erb
<div class="row mt pt"> <div class="large-5 columns"> <div class="top-pad glassy-bg"> <%= render partial: "posts/new" %> </div> </div> <div class= "large-7 columns" id="posts"> <%= render partial: @posts.reverse %> </div> </div>
Сообщения будут располагаться в обратном порядке сверху вниз, то есть наиболее свежие введенные сообщения будут первыми.
На этом этапе у нас есть сообщения с тегами, которые хранятся в базе данных с использованием двух таблиц, тегов и тегов . Таблица тегов сохраняет связь между сообщениями и тегами. Вот как выглядят наши посты:
Поиск по тегам
В этом разделе мы создадим поиски на основе области по имени тега.
Создайте метод класса с именем tagged_with(name)
который будет принимать имя указанного тега и искать связанные с ним сообщения.
приложение / модель / post.rb
def self.tagged_with(name) Tag.find_by_name!(name).posts end
Создайте переменную экземпляра, содержащую результаты на контроллере.
приложение / контроллеры / posts_controller.rb
def index if params[:tag] @posts = Post.tagged_with(params[:tag]) else @posts = Post.all end end
Добавьте маршрут get
для хранения имени тега и укажите на метод posts_controller#index
:
конфиг / routes.rb
get 'tags/:tag', to: 'posts#index', as: "tag"
После этого измените теги каждого сообщения на ссылки на метод index:
приложение / просмотров / _post.html.erb
<%=raw tag_links(post.all_tags)%>
tag_links(tags)
— это вспомогательный метод, который будет содержать логику преобразования тегов в ссылки.
приложение / хелперы / posts_helper.rb
def tag_links(tags) tags.split(",").map{|tag| link_to tag.strip, tag_path(tag.strip) }.join(", ") end
Ура! Теперь у нас есть поиск на основе тегов для наших сообщений!
Облако тегов
Давайте сгенерируем одно из этих классных облаков тегов, основанное на подсчете количества вхождений каждого тега во всех сообщениях.
Сначала создайте метод для подсчета всех тегов, связанных с сообщениями:
приложение / модели / tag.rb
def self.counts self.select("name, count(taggings.tag_id) as count").joins(:taggings).group("taggings.tag_id") end
Этот запрос группирует совпадающие tag_ids
из таблицы присоединения тегов и подсчитывает их.
Мы будем tag_cloud
их в соответствии с их количеством, создав вспомогательный метод tag_cloud
который принимает результат вызова функции tag_cloud
и CSS-классов.
приложение / хелперы / posts_helper.rb
def tag_cloud(tags, classes) max = tags.sort_by(&:count).last tags.each do |tag| index = tag.count.to_f / max.count * (classes.size-1) yield(tag, classes[index.round]) end end
Этот вспомогательный метод получит тег с максимальным количеством. Затем он зацикливается на каждом теге для расчета index
который выберет класс CSS на основе округленного значения. Затем пройденный блок будет выполнен.
Нам нужно добавить стили для разных размеров следующим образом:
Приложение / активы / tags.css.scss
.css1 { font-size: 1.0em;} .css2 { font-size: 1.2em;} .css3 { font-size: 1.4em;} .css4 { font-size: 1.6em;}
Не забудьте добавить *= require tags
в application.css .
Наконец, добавьте код для отображения тегов в представлении и примените к ним CSS-классы.
приложение / просмотров / сообщений / index.html.erb
<div class="tags-cloud glassy-bg"> <h4>Tags Cloud</h4> <% tag_cloud Tag.counts, %w{css1 css2 css3 css4} do |tag, css_class| %> <%= link_to tag.name, tag_path(tag.name), class: css_class %> <% end %> </div>
Проверьте это, наши теги в облаке!
действовать как taggable_on
После этой статьи вы сможете без проблем обработать гем act_as_taggable_on . Вы можете прочитать больше об этом на его репозитории github .
Вывод
Я надеюсь, что это руководство поможет вам понять, что входит в создание базовой системы тегов. Tag, ты это! 🙂