Rails路由基于模型属性

时间:2015-10-24 10:10:54

标签: ruby-on-rails ruby-on-rails-4 routes

参考Rails url options based on model attribute,我有一个建议的解决方案,但我不确定这是否是继续进行的方式。我也希望根据模型的属性为seo目的创建路径。在这里。

我有商业模式,生成的路线是/businesses/id。使用friendlyid gem,它变为businesses/slug

但是,我希望路线成为/business-type/business-name-and-address

参考Code Connoisseur's blog

# 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

这样做可以让我达到我想要的效果,但我不确定这是否可行。首先,此方法将创建与业务表中的行数一样多的路由。这会对应用程序的性能或其他方面产生不利影响吗?

喜欢听到大家的声音!

1 个答案:

答案 0 :(得分:0)

  

生成的路由(使用friendlyid gem)

生成的路线仍然与没有friendly_id的路线相同:

#url.com/businesses/: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)

关于你的动态路线 - 它们可能会起作用,但它们看起来很严重。

如果您要我批评自定义代码,我会写一个更新;我认为以上将实现你想要的。