簡體   English   中英

如何取回 ActiveRecord 而不是 ActiveRecord 關系?

[英]How do I get back an ActiveRecord instead of an ActiveRecord relation?

使用 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">]>

您可以使用find_by而不是where - 源代碼很簡單:

def find_by(*args)
  where(*args).take
end

另一種方法是調用.first[0] ,但如果你的where有很多記錄,這會很慢,因為它會在選擇第一個之前將它們全部加載到內存中。 如果使用limit(1) ,那么這些方法的速度將是可以接受的。

有多種方法可以從ActiveRecord::Relation獲取ActiveRecord對象。調用的結果

results = State.joins(:country).where( search_criteria.join(' and '),
                                       name.upcase) 

返回一個ActiveRecord::Relation 當您在ActiveRecord中使用where子句時,情況總是如此。 為了獲得特定的ActiveRecord對象,您可以:

  • 使用find_by方法返回它在數據庫中找到的第一個實例。 請注意,這不會返回所有符合條件的記錄。 * 例如, User.find_by(first_name: "Mark")將返回一個ActiveRecord對象,其中包含第一個名字為“Mark”的記錄
  • ActiveRecord::Relation集合上使用first一種方法。 例如, 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

大多數 ActiveRecord 方法返回 ActiveRecord::Relations 以提供流暢的 API(如果您願意的話,語法上令人愉悅的方法鏈接)。 我認為這是一個設計決定。 有一些方法可以打破這種情況,例如first (實際上是對find_nth!(0)的調用)、 last to_ato_sql和其他一些方法。

因此,我發現“周圍”的方法是使用.first ,我真正打算得到一個且只有一個結果,正如 Mark 和 maxple 所建議的那樣。 我還認為這可能是唯一的方法之一。

這個: https ://github.com/rails/rails/blob/603ebae2687a0b50fcf003cb830c57f82fb795b9/activerecord/lib/active_record/querying.rb

而這個(查詢委托了它的大部分方法): https ://github.com/rails/rails/blob/603ebae2687a0b50fcf003cb830c57f82fb795b9/activerecord/lib/active_record/querying.rb

可能值得瀏覽。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM