Rails Перенаправляет Старые Url-Адреса

Здесь я опишу, как я боролся с перемещением страниц на новые URL-адреса.

Эта статья предназначена для новичков в Ruby On Rails. Изначально у меня есть свой проект на Ruby on Rails, структура url в нем выглядит так: /locale/group/product пример: /ru/bar-code-scanners/datalogic-magelan-1100i группа И продукт это постоянная ссылка — строка, используемая для поиска в БД по идентификатору местоположения.

Проблема в том, что пользователи, добавляющие контент на сайт, иногда допускают ошибки в постоянной ссылке.

Вот пример: /ru/bar-code-scanners/datalogic-magelan-1100i Ошибка в том, что Магелан пишется с двумя ll - маг я буду ан.

Но товар добавлен относительно давно и страница уже проиндексирована поисковыми системами, поэтому задача — исправить постоянную ссылку и настроить перенаправление на новый URL. Конечно, эту проблему можно решить на уровне nginx или apache. Но обычно доступ к веб-серверу имеют только администраторы, да и плюс редактирование редиректа для нескольких локалей — тоже довольно рутинная задача.

Поэтому я решил автоматизировать это дело, для этого создал простую модель 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. Добавьте соединение в модель перенаправления.



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

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

Rails расширяет нашу модель и ее атрибуты с помощью очень удобного _changed? методы.

и был.

Все, что вам нужно сделать, это добавить обратный вызов after_save, который будет отслеживать изменения и, при необходимости, создавать новую запись модели перенаправления.



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

И не забудьте добавить статус 301 - переехал навсегда.

По умолчанию — 302 — перемещено временно.

Думаю, что приводить здесь код второго контроллера нет смысла, поскольку он аналогичен.

Еще отмечу, что в реальном коде проекта поиск 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 для управления и отслеживания всех перенаправлений.

Теги: #ruby onrails #redirect #ruby #ruby onrails

Вместе с данным постом часто просматривают: