【发布时间】:2016-01-23 20:29:10
【问题描述】:
关于Rails url options based on model attribute,我有一个建议的解决方案,但我不确定这是否是继续的方法。我还希望根据模型的属性创建路由以用于 seo 目的。就这样吧。
我有一个商业模式,生成的路由是/businesses/id。使用friendlyid gem,变成businesses/slug
但是,例如,我希望路由变为/business-type/business-name-and-address。
# app/models/dynamic_router.rb
class DynamicRouter
def self.load
Ttt::Application.routes.draw do
Business.all.each do |biz|
get "/#{biz.slug}", :to => "businesses#show", defaults: { id: biz.id, name: biz.name, type: biz.type, address: biz.address }
end
end
end
def self.reload
Ttt::Application.routes_reloader.reload!
end
end
# config/routes.rb
DynamicRouter.load
resources :businesses # still preserve old routes for 301 redirect in businesses#show
# app/controller/businesses_controller.rb
def show
@business = Business.cached_find(params[:id])
if request.path != @business.slug
redirect_to @business.slug, :status => :moved_permanently
else
...
end
end
end
# app/models/business.rb
after_save :reload_routes
def normalize_friendly_id text
# slug is changed here and works in conjunction with FriendlyID
# and keeps record of old routes (/business/xxx-xxx) for 301 redirects
"/#{self.type.parameterize}/sg/#{self.name.parameterize}-#{self.address.parameterize}"
end
def reload_routes
if slug.blank? || name_changed? || address_changed? || type_changed?
DynamicRouter.reload
end
end
# app/helper/business_helper and application_controller.rb
# to still be able to use business_path just like the defauilt url_helper,
# override it in the relevant files
def business_path business, options={}
path = ""
path = "#{business.slug}"
# this part can be and should be more robust
if options[:some_param]
path += "?some_param=#{options[:some_param]}"
end
path += "##{options[:anchor]}" if options[:anchor]
return path
end
我现在可以通过/businesses/xxx 或新的/type/name-address 路由访问business#show 页面,前者可以301 重定向到后者。
每当创建新业务时,路由将通过 after_save 回调重新加载,并且将创建到该新业务的新路由,而无需重新加载应用程序。
如果业务再次更新,其路由从/type1/name1-address1更改为/type1/name2-address1,则第一条路由将成为死链接。为了解决这个问题,我使用了 high_voltage gem,并覆盖了invalid_page 方法以将这条路线重定向回business#show
# app/controller/pages_controller
class PagesController < ApplicationController
include HighVoltage::StaticPage
def invalid_page
slug = FriendlyId::Slug.find_by_slug("/" + params[:id])
if slug && slug.sluggable_type == "Business"
redirect_to slug.sluggable.slug, :status => :moved_permanently
else
raise ActionController::RoutingError, "No such page: #{params[:id]}"
end
end
end
end
这样做可以让我实现我想要的,但我不确定这是否是要走的路。一方面,此方法将创建与业务表中的行数一样多的路由。如果有的话,这会对应用程序的性能或其他方面产生不利影响吗?
希望收到大家的来信!
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-4 routes