Gem 怎样只用 friendly_id,禁用主键 id

Peter · 2015年08月24日 · 最后由 peter 回复于 2015年08月26日 · 3103 次阅读

https://github.com/norman/friendly_id

一般用来隐藏真实的主键 id, 比如 把 http://www.example.com/users/123 变成 http://www.example.com/users/joe-schmoe

用来防止按 ID 采集,或者暴露真实用户或商品销售数目等

部署完一切看上去都很完美,但我今天试着用 http://www.example.com/users/123 访问一下,结果发现完全可用!!!

请问如何禁用用户用 123 作参数访问,只能通过 http://www.example.com/users/joe-schmoe 来访问呢?

谢谢

1 楼 已删除

可以不用这个 friendly_id gem

然后 routes.rb 里面删掉默认的 users#show,添加一个 get 'user/:username' => 'users#show'

class UsersController < ApplicationController
  def show
    @user = User.where('lower(username) = lower(?)', params[:username]).first
  end
end

原来还有 gem,原来还有很多东西要考虑,我就是直接在 controller 里写

@studio = Studio.find_by(domain: params[:studio_domain])

是不是图音图森破了?

create_table :users, id: false do |t|
.....

class User < ActiveRecord::Base
  self.primary_key = :username
.....
@user = User.find(params[:id])
return render_404 if @user.id.to_s == params[:id]

#2 楼 @libuchao #3 楼 @chairy11 谢谢,这是个办法,但改动太大,用 friendly_id 可以不改任何原来的代码

#4 楼 @mimosa 这有更详细的说明: http://ruby-journal.com/how-to-override-default-primary-key-id-in-rails/ 不但改动大,而且处理 association 的时候会有问题

#5 楼 @xmonkeycn 谢谢,你一句话点醒梦中人,你的办法真是太太太棒了!!! 建议给 friendly_id 的 README.rdoc 发 pull request,他们根本没有说明这个问题,难道用这个 Gem 的人只是考虑漂亮和 SEO,没有考虑过隐藏主键的事?

定义一个方法不就好了。

def find_by_friendly_id(id)
  first_name, last_name = id.split('-')
  find_by! first_name: first_name, last_name: last_name
end

#7 楼 @rei

谢谢,我不是真的找用户,是“比如”。

定义方法太复杂了,还要改 view 和 route,如果用 friendly_id,所有原来的代码都不用改,而且可以自动自成漂亮的 Url。

#5 楼 的方法已经足够好了。

#8 楼 @peter 定义方法为什么要改 view 和 route?MVC 不就是为了解藕么。

如果你说的是生成 url。

def to_param
  "#{first_name}-#{last_name}"
end

#9 楼 @rei 你一直是论坛正能量,也愿意花时间帮助大家,先给你点个赞。

一般情况下不要改 view 和 route,Product.find(params[:id])edit_product_url(@product)之类的都不用改,我 #8 楼 说错了。

基于我对你的了解,你可能不太喜欢依赖过多的 Gem,但在这个问题上,用 to_param 和 定义一个方法不太适合我的情况,我的情况会更复杂。主帖的 user 只是一个例子而已。

比如说现在做一个产品的 CRUD,把产品名称而不是产品 id 放在 url,url 中可能还有除 id 之外的其它参数,产品名称可能涉及英文和字母外的特殊字符,有可能还会重名,可能还会因为 SEO 的原因改名 (要考虑改名后会有坏链),这时写一个复杂的 to_param 已经不能解决问题,应该添加一个 unique 的 slug 字段存储转换后的产品名称以及“历史名称” ,如果重名还要做一些处理。更麻烦的是不只是产品要这样处理,比如 用户,产地,厂商等 controller 都要这样处理。

如果只是 to_param 这个链接对此方法有更多说明: https://gist.github.com/cdmwebs/1209732

文章最后也推荐用 friendly_id gem,因为“历史名称”不是一两句话就可以搞定。

PS: 关于中文等特殊字符处理: http://waynechu.logdown.com/posts/205700-rails-web-site-no-longer-displays-only-id

#12 楼 @peter 情况越复杂,定制程度越高,改 gem 越麻烦。不过你用得爽我也不反对。

如果只要通过用 friendly id 来查找,用

User.find_by_friendly_id(params[:id])

不要用

User.friendly.find(params[:id])

#15 楼 @quakewang 谢谢!想问一下,你是怎么找到这个方法的,我 find_by_friendly_id 只搜索到这个页面: http://www.rubydoc.info/github/norman/friendly_id/FriendlyId/FinderMethods:find_by_friendly_id

需要 登录 后方可回复, 如果你还没有账号请 注册新账号