参考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
路径访问商家#show页面,前者可以301重定向到后者。
每当创建新业务时,路由将通过after_save回调重新加载,并且将创建到该新业务的新路由,而无需重新加载应用程序。
如果业务再次更新,并且其路由从/type1/name1-address1
更改为/type1/name2-address1
,则第一条路线将成为死锁。为了解决这个问题,我使用了high_voltage gem,并覆盖invalid_page
方法将此路由重定向回企业#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
这样做可以让我达到我想要的效果,但我不确定这是否可行。首先,此方法将创建与业务表中的行数一样多的路由。这会对应用程序的性能或其他方面产生不利影响吗?
喜欢听到大家的声音!
答案 0 :(得分:0)
生成的路由(使用
friendlyid
gem)
生成的路线仍然与没有friendly_id
的路线相同:
区别在于friendly_id
引入了几种非常酷的方法,这些方法填充了路径帮手&amp;使用slug
查询(finders):)
所以实际上,你仍将params[:id]
传递给你的控制器。
只想清除它。
我希望路线成为
/business-type/business-name-business-address
简单的解决方案是更改db(custom slugs)中 slug 的情况:
#app/models/business.rb
class Business < ActiveRecord::Base
extend FriendlyId
friendly_id :name_and_address, use: :slugged
def name_and_location
"#{name}-#{address}"
end
end
给出的例子如下:
bob = Person.create! :name => "Bob Smith", :location => "New York City"
bob.friendly_id #=> "bob-smith-from-new-york-city"
如果您这样做,可以通过在cmd
中运行以下命令来影响数据库中的更改:
$ rails c
$ Business.find_all(&:save)
关于你的动态路线 - 它们可能会起作用,但它们看起来很严重。
如果您要我批评自定义代码,我会写一个更新;我认为以上将实现你想要的。