在Ruby on Rails中定义全局对象的最佳方法

时间:2014-11-13 11:13:16

标签: ruby-on-rails ruby object model-view-controller

我的应用程序有两个型号Category和Product

产品属于类别。

我创建了一个导航栏下拉列表,要求@category和@product对象在整个应用程序中可用(导航栏显示在应用程序的每个页面上。)

我可以解决的问题是放置这些基本定义的最佳位置,而不是在每个页面定义中多次定义它们。

我需要定义以下内容:

@category = Category.all

@products = @category.products.all

导航栏循环将看起来像这样。

<% @category.each do |c| %>
  <%= c.name %>
  <% @products.each do |p| %>
    <% link_to product_path(p) do %>
      <%= p.name %>
    <% end %>
  <% end %>
<% end %>

我是一个铁杆新手,所以我相信这里有一些错误,但任何帮助都会非常感激!

2 个答案:

答案 0 :(得分:5)

如果您在应用的每个页面中都需要它们,可以在ApplicationController before_filter中设置它们:

class ApplicationController
  before_filter :get_categories

  # ...
  private
  def get_categories
    @categories = Category.includes(:products)
  end
end

然后,你可以写在你的观点中:

<% @categories.each do |category| %>
  <%= category.name %>
  <% category.products.each do |product| %>
    <%= link_to p.name, p %>
  <% end %>
<% end %>

我还修复了一些其他错误和常规不兼容问题。

答案 1 :(得分:1)

以下代码不正确。

@category = Category.all
@products = @category.products.all

此代码将@categories分配给所有类别,然后尝试获取产品。除非您在Category模型中定义了products类方法,否则它将无法工作。但我不这么认为,否则你只需要致电Product.all

此外,在下面的代码中,您尝试显示每个类别的产品列表,这绝对不适用于之前的两个分配。根据您要实现的目标,您无法预先指定@products,因为您希望将产品用于特定类别。

让我们在代码中内嵌所有内容。

<% Category.all.each do |category| %>
  <%= category.name %>
  <% category.products.each do |product| %>
    <%= link_to product_path(product) do %>
      <%= product.name %>
    <% end %>
  <% end %>
<% end %>

下一步是让代码更高效,让你无处不在。

<% Category.select(:id, :name).each do |category| %>
  <%= category.name %>
  <% category.products.select(:id, :name).each do |product| %>
    <%= link_to product_path(product) do %>
      <%= product.name %>
    <% end %>
  <% end %>
<% end %>

您可以使用pluck,但它会返回一个数组,并且需要更多操作。但是,它的性能更高。

<% Category.pluck(:id, :name).each do |category_id, category_name| %>
  <%= category_name %>
  <% Product.where(category_id: category_id).pluck(:id, :name).each do |product_id, product_name| %>
    <%= link_to product_name, product_path(id: product_id) %>
  <% end %>
<% end %>

在视图中链接所有这些方法并不是一个好主意,让我们将一些代码提取到模型中。

class Category
  def self.simple_listing
    order(:name).pluck(:id, :name)
  end
end

class Product
  def self.simple_category_listing(category_id)
    where(category_id: category_id).order(:name).pluck(:id, :name)
  end
end

<% Category.simple_listing.each do |category_id, category_name| %>
  <%= category_name %>
  <% Product.simple_category_listing(category_id).each do |product_id, product_name| %>
    <%= link_to product_name, product_path(id: product_id) %>
  <% end %>
<% end %>

您可以将所有这些代码留在视图中,或将其提取为部分代码。您甚至不需要在过滤之前添加控制器,也不需要将其设置为“全局”。代码是自包含的,不会使用实例变量污染名称空间,并且可以在需要时轻松放置。