我现在有一条像
这样的路线get 'book/:id' => 'books#show', as: :book
创建该网址的代码是:
book_path @book
在控制器中:
@book = Book.find(params[:id])
到目前为止一切顺利。现在,这个id显然是内部的ActiveRecord或数据库主键。
相反,我会(在这个虚构的例子中)使用ISBN。我可以这样做:
get 'book/:isbn' => 'books#show', as: :book
book_path(isbn: @book.isbn)
@book = Book.find_by(isbn: params[:isbn])
这有点冗长;我想在整个应用程序中使用此模型的约定“isbn”,并且任何人都不需要关心它。所以,我希望我的3行看起来像这样:
get 'book/:isbn' => 'books#show', as: :book
book_path @book # (!)
@book = Book.find(params[:isbn]) # (!)
是否可以配置路线以实现我的愿望?显然,这应该自动无处不在,至少对于用户在URL中看到ISBN的GET请求。
如果重要,#isbn
属性不是通常意义上的主键,但保证表中只有一个具有特定ISBN的记录。所以至少这部分主键合同已经完成。
答案 0 :(得分:0)
要覆盖Rails默认:id
参数,您可以使用to_param
方法:
class Book < ActiveRecord::Base
def to_param # overridden
isbn
end
end
在控制器中:
book = Book.find_by(isbn: '123456')
如果您对使用任何宝石没有任何问题,那么我建议您查看friendly_id宝石。在这种情况下,这样做很好。
答案 1 :(得分:0)
在routes.rb
中,使用匹配将/book/:isbn
与book#show
匹配
match '/book/:isbn' => 'book#show', via: :get, as: :show_book
在book.rb中,您可以根据isbn而不是id重写find方法。有点像:
def self.find(*args)
c = Book.select("id").find_by(name: args[0])
args[0] = c.id
super(args)
end
这将首先通过isbn
查找,然后使用id
,它将调用原始查找方法。 (我没有对此进行测试,您必须修改它以使其适用于多个isbn
s)
但我不确定这是否值得推荐以及会出现什么警告。
相反,为什么不使用find_by_isbn[params[:isbn]]
?它比find_by(:isbn, params[:isbn])
更具可读性。