在Active Record中使用范围的方法

时间:2015-09-26 15:22:12

标签: ruby-on-rails ruby activerecord

我是Active Record的新手,尽管阅读了很多文档,但我还是找不到办法。我知道这不是处理事情的正确方法,理想情况下,下面的映射逻辑应该存在于另一个表中,但是现在这似乎是处理它的最简单方法。

我在数据库中有以下信息,我想以特殊方式检索它。我有:

|    locations    | value |
|----------------|-------|
|     brazil     |   20  |
|     europe     |   30  |
| restoftheworld |   35  |

我想要一个自定义的getter方法或范围,用于检查和查找相应的条目。在伪代码中有类似的东西:

def findbylocation(location)
  if location exists 
    return row
  elsif location.in_eu?
    return row of 'europe'
  else
    return row of 'restoftheworld'
end

写这个的最好方法是什么?它是范围还是方法?

注意:我使用https://github.com/hexorx/countries进行欧盟检查,因此没有问题。

3 个答案:

答案 0 :(得分:1)

这取决于。如果你想在内存中进行区域验证,当你在问题的伪代码中写入时,你必须使用class method(或instance method,具体取决于你将如何使用它)。例如,如果对where子句进行区域验证,则应使用scope方法。

这是因为scope会返回ActiveRecord::Relation,因此您可以链接更多“范围”方法。如果更改范围的返回类型对象,则会失去链的能力,这是毫无意义的。

我对如何使用findbylocation方法以及它的行为方式感到有些困惑。无论如何,我强烈建议您阅读this article,这很好地解释了rails中scopesmethods之间的区别。

答案 1 :(得分:-1)

首先,范围方法。

它们基本上只是Rails方法的简写。

  

我是activerecord的新手

好的,所以我认为您遇到了问题,因为您的表结构不正确。

ActiveRecord为我们提供associations的力量。这是一个抽象层,可用于在表中创建关系,允许您执行查找而无需调用100个查询。

#app/models/location.rb
class Location < ActiveRecord::Base
   has_many :cities #-> you can replace "city" with anything here
   scope :findbylocation, ->(continent) { find_by(name: continent) }
end

#app/models/city.rb
class City < ActiveRecord::Base
   #columns id | location_id | name | etc | created_at | updated_at
   belongs_to :location
end

这使您能够调用以下内容:

@location = Location.find_by name: "europe"

@location = Location.findbylocation "europe"

这将填充@location对象,然后您可以调用以下内容:

@location.cities.each do |city|
   city.name #-> Bangalore

您必须了解关系数据库的强大功能,尤其是当您构建多个对象时:

enter image description here

我相信您遇到的问题是您没有正确地模块化您的数据。 IE,你把它全部放在一个&#34;位置&#34;数据表,当真的,你应该将 locations 作为一个表,并将 cities (或其他)放在另一个表中。

这样,你就不会试图直接看一切;您正在查找所需的特定位置记录,并通过ActiveRecord将相关数据提取出来。

答案 2 :(得分:-1)

好的,我解决了。我不确定这是不是最好的方法。如果您知道更好的解决方案,请随意改进或提出其他建议。我创建了以下方法:

def self.by_location(location)
  if LocationValue.exists?(:location => location)
    where(location: location)
  elsif location.in_eu?
    where(location: 'europe')
  else
    where(location: 'restoftheworld')
  end
end