Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Rails переадресация ветхих url

Anna | 20.06.2014 | нет комментариев
Здесь опишу как я боролся с переездом страниц на новые url.
Эта заметка рассчитана на новичков в Ruby On Rails.Первоначально имею свой план на Ruby on Rails, конструкция url в нем выглядит дальнейшим образом: /locale/group/product
пример: /ru/bar-code-scanners/datalogic-magelan-1100i

group и product это permalink — строка по которой осуществляется поиск в DB, в место id.

Задача в том, что пользователи которые добавляют контент на сайт изредка допускают ошибки в permalink.
Вот пример: /ru/bar-code-scanners/datalogic-magelan-1100i
Оплошность в том, что магелан пишется с двумя ll — magellan.
Но товар был добавлен касательно давным-давно и страница теснее проиндексирована поисковиками, по этому стоит задача поправить permalink и настроить пере адресацию на новейший URL.

Безусловно эту задачу дозволено решить на ярусе nginx либо apache. Но к web серверу традиционно есть доступ только у менеджеров и плюс править redirect еще и для нескольких locale достаточно рутинная задача.
По этому я решил это дело автоматизировать, для этого сотворил простенькую модель Redirection с полиморфной связью, то есть она может принадлежать как Product так и Group.

Файл миграции 20131113223332_create_redirections.rb

class CreateRedirections < ActiveRecord::Migration
  def change
    create_table :redirections do |t|
      t.references :redirectable, polymorphic: true
      t.string :permalink

      t.timestamps
    end
  end
end

А вот как выглядит сама модель Redirection:

class Redirection < ActiveRecord::Base
  attr_accessible :permalink

  belongs_to :redirectable, polymorphic: true

  def self.product(permalink)
    redirection = Redirection.where(permalink: permalink, redirectable_type: "Product").first
    redirection.redirectable if not redirection.nil?
  end

  def self.group(permalink)
    redirection = Redirection.where(permalink: permalink, redirectable_type: "Group").first
    redirection.redirectable if not redirection.nil?
  end

end

Сейчас осталось подправить всякую модель, для которой необходимо настроить пере адресацию Group и Product.
Добавляем связь с моделью Redirection.

  has_many   :redirections, as: :redirectable, :dependent=>:destroy

Сейчас необходимо реализовать отслеживать метаморфозы признака permalink и при необходимости создавать запись Redirection.
К счастью все модели которые имею permalink наследованны от одного моего промежуточного класса AbstractContent. Так что довольно добавить код отслеживания метаморфоза permalink только в этом классе, не нарушая тезисов DRY.

И вот за что я люблю Rails — само отслеживание реализовать оказалось элементарно. Rails расширяет нашу модель и ее признаки дюже комфортными способами _changed? и _was.

Все что необходимо, это добавить callback after_save, тот, что и будет отслеживать метаморфозы и в случае необходимости сделает новую запись модели Redirection

class AbstractContent < ActiveRecord::Base

  self.abstract_class = true

  after_save :check_permalink_changes

  def check_permalink_changes
    if self.permalink_changed?
      if self.permalink_was
        self.redirections.create!(permalink: self.permalink_was)
      end

    end
  end

end

Осталось только настроить саму переадресацию в контроллере

class GroupsController < ApplicationController

  def show
    @group = Group.find_by_permalink(params[:id]) 
    if @group.nil?
      @group = Redirection.group(params[:id]) || not_found
      redirect_to group_path(@group), status: 301
    end
  end
end

И не забываем добавить status 301 — moved permanently. По умолчанию возвращается 302 — moved temporarily.

Думаю, что приводить код второго контроллера тут нет смысла потому, что он аналогичен.
Так же подмечу, что в настоящем коде плана поиск find_by_permalink осуществляется через кеш, find_in_cache отсель убрал для облегчения примера.

Для комфортного вызова ошибки 404 добавил в ApplicationController способ not_found дерзкий Exception.

  def not_found
    raise ActionController::RoutingError.new('Not Found')
  end

К стати, если не охота рыться в production.log, а есть желание просматривать все ошибки по запросам URL именно требуемой нам конструкции /group/product. То тут комфортно добавить логирование всех вызовов not_found в обособленный файл.

P.S. Ну и дозволено еще добавочно добавить RedirectionsController для управления и отслеживания всех переадресаций.

Источник: programmingmaster.ru
Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB