使用Rails 5.如何获取ActiveRecord而不是ActiveRecord关系?我是下面的模型
class State < ActiveRecord::Base
belongs_to :country
...
def self.cached_find_us_state_by_name(name)
Rails.cache.fetch("#{name.upcase} US") do
find_us_state_by_name(name)
end
end
# Look up a US state by its full name
def self.find_us_state_by_name(name)
search_criteria = ["upper(states.name) = ? "]
search_criteria.push( "states.country_id = countries.id " )
search_criteria.push( "countries.iso = 'US' " )
results = State.joins(:country).where( search_criteria.join(' and '),
name.upcase)
end
但是当我使用这些方法查找项目时,我回来的是一个ActiveReocrd关系......
2.4.0 :004 > State.cached_find_us_state_by_name('Ohio')
=> #<ActiveRecord::Relation [#<State id: 3538, name: "Ohio", country_id: 233, iso: "OH">]>
这是后来的问题,特别是......
ActiveRecord::AssociationTypeMismatch: State(#70288305660760) expected, got State::ActiveRecord_Relation(#70288290686360)
from /Users/davea/.rvm/gems/ruby-2.4.0@global/gems/activerecord-5.0.1/lib/active_record/associations/association.rb:221:in `raise_on_type_mismatch!'
from /Users/davea/.rvm/gems/ruby-2.4.0@global/gems/activerecord-5.0.1/lib/active_record/associations/belongs_to_association.rb:12:in `replace'
编辑:根据给出的建议,我将方法改为
def self.cached_find_us_state_by_name(name)
Rails.cache.fetch("#{name.upcase} US") do
find_us_state_by_name(name)
end
end
# Look up a US state by its full name
def self.find_us_state_by_name(name)
search_criteria = ["upper(states.name) = ? "]
search_criteria.push( "states.country_id = countries.id " )
search_criteria.push( "countries.iso = 'US' " )
results = State.joins(:country).where( search_criteria.join(' and '),
name.upcase).take
end
但是,我仍然得到一个ActiveRecord :: Relation
2.4.0 :011 > State.cached_find_us_state_by_name('Ohio')
=> #<ActiveRecord::Relation [#<State id: 3538, name: "Ohio", country_id: 233, iso: "OH">]>
答案 0 :(得分:0)
您可以使用find_by
代替where
- 源代码很简单:
def find_by(*args)
where(*args).take
end
另一种方法是拨打.first
或[0]
,但如果您的where
有大量记录,这将会很慢,因为它会在选择之前将它们全部加载到内存中第一。如果使用limit(1)
,那么这些方法将是可接受的快速。
答案 1 :(得分:0)
有多种方法可以从ActiveRecord
获取ActiveRecord::Relation
对象。调用
results = State.joins(:country).where( search_criteria.join(' and '),
name.upcase)
返回ActiveRecord::Relation
。当您在where
中使用ActiveRecord
子句时,情况总是如此。为了获得特定的ActiveRecord
对象,您可以:
find_by
方法返回它找到的数据库中的第一个实例。请注意,这不会返回符合条件的所有记录。 *例如,User.find_by(first_name: "Mark")
将返回一个ActiveRecord
对象,其中包含名为&#34; Mark&#34; first
集合上的ActiveRecord::Relation
方法。例如,User.where(first_name: "Mark").first
与前一个示例的作用相同。最后,你可以这样写:
User.where(first_name: "Mark") do |u|
puts u.last_name
end
这允许您一次遍历ActiveRecord::Relation
集合一条记录。因此,对于您的示例,它看起来像这样:
results.each do |res|
# do stuff
end
答案 2 :(得分:0)
大多数ActiveRecord方法返回ActiveRecord :: Relations,以便提供流畅的API(如果你愿意的话,语法上令人愉悦的方法链接)。我认为这是一个设计决定。有一些方法可以解决此问题,例如first
(实际上是对find_nth!(0)
的调用),last
to_a
,to_sql
以及其他一些方法。
所以,我发现“周围”的方式就是使用.first
我真正想要得到一个而且只有一个结果,正如Mark和maxple所暗示的那样。我也认为这可能是唯一的方法之一。
这个(查询代表大部分方法):https://github.com/rails/rails/blob/603ebae2687a0b50fcf003cb830c57f82fb795b9/activerecord/lib/active_record/querying.rb
可能值得一试。