在Rails中自动创建单个产品页面

时间:2012-10-08 19:48:16

标签: ruby-on-rails-3 url url-rewriting

我将回到几个月前写的一个应用程序,并尝试进行一些小的调整。我目前有一个模型Product和一个目录页面,其中所有产品都使用each循环列出Product中的所有条目。

为了确保网站安全,我已将http://.../products/...置于身份验证登录之后,因此只有拥有密码的用户才能看到/products/index,编辑产品详细信息并查看产品一个时间(显示页面)。

我现在想要从列出的所有产品页面链接到只有一个产品详细信息的页面(即单个产品的页面)。

我知道我可以使用Product的查找功能找到Product ID模型中的产品,但是,如何自动为此商品的商家信息创建合理的网址?< / p>

总之,如果我在一个页面上列出了10个产品,那么让用户点击产品并将其路由到名为http://..../shop/specific_products_name的页面的最佳方法是什么?我已经阅读了一下,似乎to_param可能有一些好处,但我正在努力找出一种合理的方法来创建这些页面

感谢您的时间

1 个答案:

答案 0 :(得分:1)

这是一个基本的传统控制器设置:

首先,这是路由快捷方式语法:

# config/routes.rb
...
resources :products
...

这是控制器,可以加载index上的所有产品,只加载show上的一个产品。

# app/controllers/products_controller.rb
class ProductsController 
  def index
    @products = Product.all
  end

  def show
    @product = Product.find(params[:id])
  end   
end

路线文件中的那一行为我们提供了这些路线(其中包括):

  • /products转到products_controller#index
  • /products/:id转到products_controller#show,并将params [:id]设置为给定的数字

在您查看时,以最少的工作量获取漂亮网址的最简单方法是覆盖to_param

to_param是Rails用于将模型转换为url / request中的表示的内容。

默认情况下,就是这样:

class Product
  def to_param
    self.id
  end
end

因此,当Rails对to_param的结果执行Product.find()时,find()会将其转换为to_i的整数。

如果params[:id]"24",则Product.find(params[:id])会将“24”转换为整数24。

但请考虑to_i如何与其他示例一起使用:

"100".to_i                     #=> 100
"100-flux-capacitor-2000".to_i #=> 100

换句话说,如果我们的产品参数表示为"#{id}-the-product-name",即使我们的产品#显示的网址看起来像Product.find(params[:id])/products/56-ford-taurus仍然有用。

还有一件事:

"I love the Ford Taurus".parameterize #=> "i-love-the-ford-taurus"

解决方案A

解决问题的最简单方法是覆盖to_param,如下所示:

class Product
  def to_param
    "#{id}-#{name.parameterize}"
  end
end

此方法的好处是您可以在Product模型中更改一个方法,并在代码的其余部分中更改Just Works。

缺点是您的网址如下:

/products/56-ford-taurus

而不是:

/products/ford-taurus

解决方案B

如果您想要后一个示例,可以在Products表中维护slug列。

示例:

Product
  id: 58
  name: Ford Taurus
  slug: ford-taurus

然后你可以像这样覆盖to_param:

class Product
  def to_param
    slug
  end
end

现在,params [:id]看起来像“ford-taurus”。

由于find()想要一个整数,

Product.find("ford-taurus")将不再有效,因此您可以将Product.find(params[:id])替换为Product.find_by_slug(params[:id])

你必须确保每件产品都有一个独特的slu ..

您可以通过以下方式自动化段塞创建过程:

class Product
  before_create :make_slug

  private
  def make_slug
    self.slug = name.parameterize
  end
end

这样,你只需要在创建时设置产品的名称,保存它,它的slug将成为URL友好的“无论产品名称是什么”。

  • 另外一方:您的网址现在只包含产品名称,不含丑陋的产品ID。
  • 向下:更改slug产品会破坏URL,这就是为什么我的before_filter示例仅在创建时设置slug而不是任何时候保存产品。

现在Rails将生成您想要的URL类型,您可以在以下视图中生成指向这些产品的链接:

# This would be in views/index.html.erb
<% @products.each do |product| %>
  <%= link_to product.name, product %>
<% end %>

为每种产品提供此类html:

<a href="/products/56-ford-taurus">Ford Taurus</a> (if you used Solution A)
<a href="/products/ford-taurus">Ford Taurus</a> (if you used Solution B)