使用场景:在url中显示post的title,而不是post的id,比如url中,使用posts/one, 而不是post/1。另外一个应用到的场景中是,当post的title改变的时候,访问post旧的title可以链接到已经更新为新的title的post中,原理是使用history。
代码如下所示:
#gemfile
gem 'friendly_id', '~> 5.1.0' # Note: You MUST use 5.0.0 or greater for Rails 4.0+
#终端
rails g friendly_id #需要修改ActiveRecord::Migration为ActiveRecord::Migration[5.1]
rails g scaffold post title:string body:text description:text slug:string:uniq
#model中的post.rb
class Post < ApplicationRecord
extend FriendlyId
friendly_id :title, use: [:slugged, :history] #添加history为记录旧值
def should_generate_new_friendly_id?
title_changed?
end
end
#controller中posts_controller.rb
class PostsController < ApplicationController
def show
if request.path != post_path(@post) #当访问旧值时,链接地址会自动跳到更新后的新值中
redirect_to @post, :status => :moved_permanently
end
end
def update
@post.slug = nil #必须添加
if @post.update_attributes(post_params)
flash[:notice] = 'Post successfully updated'
redirect_to @post
else
render 'edit'
end
end
private
def set_post
@post = Post.friendly.find(params[:id]) #必须在添加friendly方法
end
end
解决中文可以作为friendly_id的问题
#gemfile
gem 'babosa'
#model
class Product < ActiveRecord::Base
extend FriendlyId
#原本是input.to_s.parameterize,但是parameterize只支持英文跟數字,所以改用babosa的to_slug
def normalize_friendly_id(input)
input.to_s.to_slug.normalize.to_s
end
end
friendly_id的局限
#不能使用find_by方法
User.find_by(id: params[:id]) #会报错