2017-05-04 43 views
0

我有什么

我现在有喜欢使用路径佣工非默认的属性,而不是:ID

get 'book/:id' => 'books#show', as: :book 

的代码创建一个URL路径是:

book_path @book 

在控制器:

@book = Book.find(params[:id]) 

到现在为止还挺好。现在,这个ID显然是内部的ActiveRecord或数据库主键。

我想要什么

相反,我会(在这个例子虚构)使用书号代替。我可以这样做:

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

你检查了[to_param](https://apidock.com/rails/ActiveRecord/Integration/to_param)方法吗? – Sajan

+0

我没有!谢谢,这很好,解决了两者中更紧迫的问题。事后看来,我想我更喜欢'#find',所以坚持内部ID,反正。如果你创建一个迷你答案,你会得到我的接受。 – AnoE

回答

0

要覆盖Rails的默认:id参数,你可以使用to_param方法:

class Book < ActiveRecord::Base 
    def to_param # overridden 
    isbn 
    end 
end 

并在控制器:

book = Book.find_by(isbn: '123456') 

如果你没有任何问题,使用任何宝石吧,那么我建议你应该看看friendly_id宝石。这在这种情况下做得很好。

0

在你routes.rb,使用匹配匹配/book/:isbnbook#show

match '/book/:isbn' => 'book#show', via: :get, as: :show_book 

在你book.rb,您可以覆盖为了find方法查找基于ISBN,而不是ID。沿着线的东西:

def self.find(*args) 
    c = Book.select("id").find_by(name: args[0]) 
    args[0] = c.id 
    super(args) 
end 

这将首先isbn找到并使用id,它会调用 find方法。 (我没有测试过这个,你将不得不修改它以使它与多个isbn s一起工作)

但是我不确定这是否被推荐以及它会出现什么警告。

相反,你为什么不使用find_by_isbn[params[:isbn]]?它比find_by(:isbn, params[:isbn])更具可读性。