【问题标题】:Match multiple models in single Rails route with friendly_id使用friendly_id匹配单个Rails路由中的多个模型
【发布时间】:2014-12-09 04:33:48
【问题描述】:

我有一个 Company 和一个 User 模型,两者都通过 friendly_id 使用 slug。确保 Slug 在两种模型中都是唯一的。

我想要网址:

http://www.example.com/any_company_name

http://www.example.com/any_user_name

例如/apple/tim

我不确定如何在 Rails 中实现这一点。

我尝试了以下各种排列:

routes.rb:
  resources :users, path: ''
  resources :companies, path: ''
  get '*search', to: 'my_controller#redirect'

my_controller#redirect:
  @company = Company.friendly.find(params[:search])
  redirect_to @company if @company
  @user = User.friendly.find(params[:search])
  redirect_to @user if @user

但是我无法让它工作。我可以让/apple 重定向到/companies/apple/tim 重定向到/users/tim(通过删除path: '' 选项)但这不是我想要实现的。

【问题讨论】:

    标签: ruby-on-rails friendly-id


    【解决方案1】:

    您可以使用 url_for 使用 controller#action 进行重定向,而不是使用 url 进行重定向。

    例如:

    my_controller#redirect:
      @company = Company.friendly.find(params[:search])
      redirect_to url_for(action: 'show', controller: :companies , status: :success, company_id:@company.id)
      @user = User.friendly.find(params[:search])
      redirect_to url_for(action: 'show', controller: :users, status: :success,user_id:@user.id)
    

    【讨论】:

      【解决方案2】:

      我遇到了类似的问题,并且能够通过创建具有 slug 属性和与“Sluggable”类的多态关联的 PublicSlug 模型来解决它。我还使用了我想要查询的模型中包含的 Sluggable 关注点。

      PublicSlug 模型

      class PublicSlug < ActiveRecord::Base
        extend FriendlyId
      
        friendly_id :sluggable_name, use: :slugged
      
        belongs_to :sluggable, polymorphic: true
      
        private
      
        # Generate the slug based on the title of the Sluggable class
        def sluggable_name
          sluggable.name
        end
      end
      

      Sluggable 问题

      module Sluggable
        extend ActiveSupport::Concern
      
        included do
         has_one :public_slug, dependent: :destroy, as: :sluggable
      
         delegate :slug, to: :public_slug
        end
      end
      

      公司和用户模型。

      class User < ActiveRecord::Base
        include Sluggable
      end
      
      class Company < ActiveRecord::Base
        include Sluggable
      end
      

      我现在可以使用

      查询这两个模型
      Sluggable.friendly.find(slug).sluggable
      

      重定向可以在你的控制器中处理如下:

      def redirect
        @sluggable = Sluggable.friendly.find(params[:search]).sluggable
      
        redirect_to @sluggable
      end
      

      【讨论】:

      • 当我尝试这个时,我得到:“User#slug 委托给 public_slug.slug,但 public_slug 是 nil”。
      【解决方案3】:

      基于@Essn 的回答...

      仍然使用 PublicSlug 模型:

      # app/models/public_slug.rb
      class PublicSlug < ActiveRecord::Base
        extend FriendlyId
      
        friendly_id :sluggable_name, use: :slugged
        belongs_to :sluggable, polymorphic: true
      
        validates :slug, presence: true, uniqueness: { case_sensitive: false }
      
        private
          # Generate the slug based on the title of the Sluggable class
          def sluggable_name
            sluggable.name
          end
      end
      

      还有一个值得关注的问题:

      # app/models/concerns/sluggable.rb
      module Sluggable
        extend ActiveSupport::Concern
      
        included do
          before_validation :create_public_slug
          has_one :public_slug, dependent: :destroy, as: :sluggable
          delegate :slug, to: :public_slug
      
          private
            def create_public_slug
              self.public_slug = PublicSlug.new unless public_slug.present?
            end
        end
      end
      

      在您要查找的所有模型中包含该关注点:

      # app/models/user.rb
      class User < ActiveRecord::Base
        include Sluggable
        ...
      end
      

      创建迁移:

      # db/migrate/...create_public_slugs.rb
      class CreatePublicSlugs < ActiveRecord::Migration[5.0]
        def change
          create_table :public_slugs do |t|
            t.references :sluggable, polymorphic: true
            t.string :slug
          end
        end
      end
      

      然后您可以通过以下方式查找模型:

      # app/controllers/home_controller.rb
      class HomeController < ApplicationController
        # /:slug
        def show
          @sluggable = PublicSlug.friendly.find(params[:id]).sluggable
          render @sluggable
        end
      end
      

      【讨论】:

        猜你喜欢
        • 2011-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-24
        • 1970-01-01
        • 2013-05-04
        • 1970-01-01
        相关资源
        最近更新 更多