使用 STI 的 Rails 应用程序——提取这些记录的最简单方法? [英] Rails app using STI -- easiest way to pull these records?

查看:59
本文介绍了使用 STI 的 Rails 应用程序——提取这些记录的最简单方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习使用 Rails 的方法,并且正在开发一个示例应用程序来跟踪啤酒食谱.

I'm learning my way around Rails and am working on a sample app to keep track of beer recipes.

我有一个名为 Recipe 的模型,其中包含配方名称和效率.

I have a model called Recipe which holds the recipe name and efficiency.

我有一个名为 Ingredient 的模型,它使用 STI - 它被细分为麦芽、啤酒花和酵母.

I have a model called Ingredient which is using STI - this is subclassed into Malt, Hop, and Yeast.

最后,为了链接食谱和成分,我使用了一个名为 rec_items 的连接表,其中包含 recipe_id、成分 ID 和特定于该食谱/成分组合的信息,例如数量和煮沸时间.

Finally, to link the recipes and ingredients, I am using a join table called rec_items which holds the recipe_id, ingredient_id, and info particular to that recipe/ingredient combo, such as amount and boil time.

一切似乎都运行良好 - 我可以使用 Malt.all 找到我所有的麦芽,使用 Ingredient.all 找到所有成分.我可以使用@recipe.ingredients 等找到食谱的成分...

Everything seems to be working well - I can find all my malts by using Malt.all, and all ingredients by using Ingredient.all. I can find a recipe's ingredients using @recipe.ingredients, etc...

但是,我现在正在处理我的食谱的显示视图,并且对完成以下操作的最佳方法感到困惑:

However, I'm working on my recipe's show view now, and am confused as to the best way to accomplish the below:

我想显示配方名称和相关信息,然后列出成分,但按成分类型分隔.所以,如果我有一个效率为 85% 的黑色 IPA 并且它有 5 个麦芽和 3 个啤酒花品种,输出将类似于:

I want to display the recipe name and associated info, and then list the ingredients, but separated by ingredient type. So, if I have a Black IPA @ 85% efficiency and it has 5 malts and 3 hops varieties, the output would be similar to:

BLACK IPA (85%)
Ingredient List
MALTS:
malt 1
malt 2
...
HOPS:
hop 1
...

现在,我可以拉取@recipe.rec_items 并遍历它们,测试每个 rec_item.ingredient 的 type == "Malt",然后对跃点执行相同的操作,但这似乎不是 Rails-y 也不是高效.那么最好的方法是什么?我可以使用@recipe.ingredients.all 来提取所有成分,但不能使用@recipe.malts.all 或@recipe.hops.all 来提取这些类型.

Now, I can pull @recipe.rec_items and iterate through them, testing each rec_item.ingredient for type == "Malt", then do the same for the hops, but that doesn't seem very Rails-y nor efficient. So what is the best way to do this? I can use @recipe.ingredients.all to pull all the ingredients, but can't use @recipe.malts.all or @recipe.hops.all to pull just those types.

我应该使用不同的语法吗?我应该使用@recipe.ingredient.find_by_type("Malt") 吗?在控制器中执行此操作并将集合传递给视图,还是在视图中执行此操作?我是否还需要在 Hop 和 Malt 模型中指定 has_many 关系?

Is there a different syntax I should be using? Should I using @recipe.ingredient.find_by_type("Malt")? Doing this in the controller and passing the collection to the view, or doing it right in the view? Do I need to specify the has_many relationship in my Hop and Malt models as well?

我可以使用条件语句或 find_by_type 让它按照我想要的方式工作,但我的重点是用尽可能少的数据库开销来实现这种Rails 方式".

I can get it working the way I want using conditional statements or find_by_type, but my emphasis is on doing this "the Rails way" with as little DB overhead as possible.

感谢您的帮助!

当前的基本代码:

食谱.rb

class Recipe < ActiveRecord::Base
  has_many :rec_items
  has_many :ingredients, :through => :rec_items
end

成分.rb

class Ingredient < ActiveRecord::Base
  has_many :rec_items
  has_many :recipes, :through => :rec_items
end

麦芽.rb

class Malt < Ingredient
end

Hop.rb

class Hop < Ingredient
end

RecItem.rb

class RecItem < ActiveRecord::Base
  belongs_to :recipe
  belongs_to :ingredient
end

recipes_controller.rb

recipes_controller.rb

class RecipesController < ApplicationController
  def show
    @recipe = Recipe.find(params[:id])
  end

  def index
    @recipes = Recipe.all
  end
end

更新添加

我现在无法访问连接表属性,所以我发布了一个新问题:

I'm now unable to access the join table attributes, so I posted a new question:

Rails - 使用 group_by 和 has_many :through 并尝试访问连接表属性

如果有人能帮忙解决这个问题,我将不胜感激!!

If anyone can help with that, I'd appreciate it!!

推荐答案

自从我使用 STI 已经有一段时间了,已经被烧了一两次.所以我可能会跳过一些让这更容易的 STI-fu.话说……

It's been a while since I've used STI, having been burned a time or two. So I may be skipping over some STI-fu that would make this easier. That said...

有很多方法可以做到这一点.首先,您可以为每种麦芽、啤酒花和酵母制作一个范围.

There are many ways of doing this. First, you could make a scope for each of malt, hops, and yeast.

class Ingredient < ActiveRecord::Base
  has_many :rec_items
  has_many :recipes, :through => :rec_items
  named_scope :malt, :conditions =>  {:type => 'Malt'}
  named_scope :hops, :conditions => {:type => 'Hops'}
  ...
end

这将允许你做一些事情:

This will allow you to do something line:

malts = @recipe.ingredients.malt
hops = @recipe.ingedients.hops

虽然这很方便,但在数据库方面并不是最有效的做法.我们必须执行三个查询才能获得所有三种类型.

While this is convenient, it isn't the most efficient thing to do, database-wise. We'd have to do three queries to get all three types.

因此,如果我们不是在每个食谱中谈论大量成分,那么最好只提取所有 @recipe.ingredients,然后将它们分组,例如:

So if we're not talking a ton of ingredients per recipe, it'll probably be better to just pull in all @recipe.ingredients, then group them with something like:

ingredients = @recipe.ingredients.group_by(&:type)

这将执行一个查询,然后将它们分组到 ruby​​ 内存中的一个散列中.散列将被关闭类型,看起来像:

This will perform one query and then group them into a hash in ruby memory. The hash will be keyed off of type and look something like:

{"Malt" => [first_malt, second_malt],
 "Hops" => [first_hops],
 "Yeast" => [etc]
}

然后您可以参考该集合以按您的意愿显示项目.

You can then refer to that collection to display the items however you wish.

ingredients["Malt"].each {|malt| malt.foo }

这篇关于使用 STI 的 Rails 应用程序——提取这些记录的最简单方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆