Match multiple models in single Rails route with friendly_id

最后都变了- 提交于 2019-12-03 22:53:44

问题


I have a Company and a User model, both with a slug via friendly_id. Slugs are ensured to be unique across both models.

I'd like to have URLs:

http://www.example.com/any_company_name

http://www.example.com/any_user_name

e.g. both /apple and /tim

I'm not sure how to achieve this in Rails.

I have tried various permutations of:

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

and

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

However I can't get it to work. I can get /apple to redirect to /companies/apple and /tim to redirect to /users/tim (by removing the path: '' option) but this is not what I want to achieve.


回答1:


Instead redirect with urls, you can redirect with controller#action by using url_for.

For example:

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:


I had a similar problem and was able to solve it by creating a PublicSlug model with a slug attribute and a polymorphic association to a "Sluggable" class. I also used a Sluggable concern that I included in models I would like to query.

The PublicSlug model

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

The Sluggable concern

module Sluggable
  extend ActiveSupport::Concern

  included do
   has_one :public_slug, dependent: :destroy, as: :sluggable

   delegate :slug, to: :public_slug
  end
end

Company and User models.

class User < ActiveRecord::Base
  include Sluggable
end

class Company < ActiveRecord::Base
  include Sluggable
end

I can now query both models using

Sluggable.friendly.find(slug).sluggable

The redirect could be handled in your controller as follows:

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

  redirect_to @sluggable
end



回答3:


Building off of @Essn's answer...

Still use a PublicSlug model:

# 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

And a Sluggable concern:

# 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

Include that concern in all models you want to lookup:

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

Create a migration:

# 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

Then you can lookup the model via:

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


来源:https://stackoverflow.com/questions/27371487/match-multiple-models-in-single-rails-route-with-friendly-id

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!