Here I will describe how I struggled with moving pages to new url.
This post is intended for beginners in Ruby on Rails.
Initially I have my own project on Ruby on Rails, the url structure in it looks like this: / locale / group / product
example: / en / bar-code-scanners / datalogic-magelan-1100i
group and
product is permalink - the string by which the search is performed in the DB, in the place of id.
')
The problem is that users who add content to the site sometimes make mistakes in permalink.
Here is an example: / en / bar-code-scanners / datalogic-magelan-1100i
The mistake is that Magellan is written with two ll - mage
ll an.
But the product was added relatively long time ago and the page was already indexed by search engines, so the task is to fix permalink and set up redirection to a new URL.
Of course, this task can be solved at the level of nginx or apache. But only the administrators usually have access to the web server and plus redirect is also quite a routine task for several locale.
That's why I decided to automate this business, for this I created a simple Redirection model with a polymorphic link, that is, it can belong to both Product and Group.
Migration file
20131113223332_create_redirections.rbclass CreateRedirections < ActiveRecord::Migration def change create_table :redirections do |t| t.references :redirectable, polymorphic: true t.string :permalink t.timestamps end end end
And this is what the Redirection model itself looks like:
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
Now it remains to correct each model for which you need to configure the Group and Product re-addressing.
Add a link to the Redirection model.
has_many :redirections, as: :redirectable, :dependent=>:destroy
Now you need to implement to track changes in the permalink attribute and, if necessary, create a Redirection entry.
Fortunately, all the models that have permalink inherited from one of my intermediate class AbstractContent. So it suffices to add the permalink change tracking code only in this class, without violating the principles of DRY.
And that's why I love Rails - the tracking itself turned out to be elementary. Rails extends our model and its attributes with very convenient _changed methods? and _was.
All you need is to add a callback after_save, which will track the changes and, if necessary, create a new record of the Redirection model.
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
It remains only to configure the forwarding itself in the controller
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
And don't forget to add status 301 - moved permanently. The default is 302 - moved temporarily.
I think that there is no point in citing the code of the second controller here because it is similar.
Also note that in the real project code, find_by_permalink is searched through the cache, find_in_cache is removed from here to simplify the example.
To conveniently call error 404, the not_found method called Exception was added to ApplicationController.
def not_found raise ActionController::RoutingError.new('Not Found') end
By the way, if you do not want to rummage in production.log, but there is a desire to view all the errors on the URL requests of the / group / product structure we need. Here it is convenient to add all not_found calls to a separate file.
PS Well, you can still add an additional RedirectionsController to manage and track all redirects.