Ruby on rails 用Ruby思考

Ruby on rails 用Ruby思考,ruby-on-rails,ruby,activerecord,Ruby On Rails,Ruby,Activerecord,我目前正忙于学习Ruby和Rails,由于我有C语言的背景,Ruby的一些概念是新的,有些陌生。对我来说,特别具有挑战性的是如何适应处理常见问题的“Ruby方式”,因此我经常发现自己用Ruby编写C语言,这不是我想要实现的 想象一下有这样一个模式: ActiveRecord::Schema.define(:version => 20111119180638) do create_table "bikes", :force => true do |t| t.st

我目前正忙于学习Ruby和Rails,由于我有C语言的背景,Ruby的一些概念是新的,有些陌生。对我来说,特别具有挑战性的是如何适应处理常见问题的“Ruby方式”,因此我经常发现自己用Ruby编写C语言,这不是我想要实现的

想象一下有这样一个模式:

ActiveRecord::Schema.define(:version => 20111119180638) do
    create_table "bikes", :force => true do |t|
        t.string   "Brand"
        t.string   "model"
        t.text     "description"
    end
end
数据库已经包含了几个不同的自行车。我的目标是获得数据库中表示的所有品牌的数组

这是我的密码:

class Bike < ActiveRecord::Base
    def Bike.collect_brands
        temp_brands = Bike.find_by_sql("select distinct brand from bikes")
        brands = Array.new
        temp_brands.each do |item|
          brands.push(item.brand)
        end
        brands
    end
end
class Bike

Ruby大师如何编写代码来实现这一点;dr:您的整个方法可以替换为Bike.uniq.pluck(:brand)


此功能已经存在(请参见我答案的结尾),但首先,让我们逐步了解您的代码,并使其更加地道:

首先,每个缩进级别使用两个空格,而不是四个空格、八个空格和制表符。使用两个空格。这不是个人喜好,这是Ruby社区中一个非常强大的惯例,如果您打算参与,这是非常必要的

接下来,在Ruby中使用这种模式几乎没有什么好的理由:

 brands = Array.new
 temp_brands.each do |item|
   brands.push(item.brand)
 end
如果要通过对输入数组中的每个值应用一些代码将一个数组转换为另一个数组(实际上是将一个可枚举项转换为另一个可枚举项),请使用or(同义词):

下一步,您可以利用使上述代码更加清晰:

brands = temp_brands.map &:brand 
对于新手来说,这看起来很奇怪,但是一旦你习惯了使用
map
&:field
,情况就更清楚了。一点经验将使这行代码的意图非常明显:它将
brand
方法应用于数组中的每个元素,它与以前的
{item | item.brand}
版本完全相同

现在,您的整个方法可以变成非常简单的一行:

def Bike.collect_brands
  Bike.find_by_sql("select distinct brand from bikes").map &:brand
end
内联select/distinct SQL有点难看,特别是因为ActiveRecord已经允许我们使用
select
,并使用
uniq
将结果区分开来:

def Bike.collect_brands
  Bike.select(:brand).uniq.map &:brand
end
作为最后一次迭代,我们可以使用而不是
map
从我们感兴趣的结果中只提取字段。但是,由于
pluck
实际上修改了正在生成的SQL,使其只包含正在被提取的字段,因此我们可以省略
select(:brand)
部分,我们的代码可以归结为一个非常短的单行,其中包含两个链式方法:

def Bike.collect_brands
  Bike.uniq.pluck(:brand)
end
请注意,顺序很重要,因为
pulk
始终返回一个数组,而不是准备好进行额外方法链接的ActiveRecord关系
Bike.pluck(:brand)。uniq
将从每个记录中选择品牌(
从bikes中选择品牌
),然后在Ruby中,将数组缩减为唯一项。这可能是一个非常昂贵的操作


就是这样,
Bike.uniq.pulk(:brand)
。作为一名C程序员,您会发现,使用小循环执行的许多重复任务实际上已经通过语言本身或支持库为您解决了。一旦你学会了编写惯用的Ruby和Rails代码,那么你没有编写的代码数量可能会非常惊人。

继续问这个问题会更好。谢谢你指点我去那个地方。我不知道有这样的事情存在。当我读到“从来没有”这句话时,我几乎投了反对票,但后来却投了反对票:)我还是太啰嗦了。ActiveRecord非常聪明,因此
.select(:field).uniq.pulk(:field)
.uniq.pulk(:field)
是同义词。非常感谢您花时间提供如此详细的答案。我真的很感激。
def Bike.collect_brands
  Bike.uniq.pluck(:brand)
end