2017-02-10 72 views
0

使用Rails 5.如何獲得ActiveRecord而不是ActiveRecord關係?我ahve下面的模型如何取回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">]> 

這將在後面cauisng的問題,特別是查找一個項目.. 。

ActiveRecord::AssociationTypeMismatch: State(#70288305660760) expected, got State::ActiveRecord_Relation(#70288290686360) 
    from /Users/davea/.rvm/gems/[email protected]/gems/activerecord-5.0.1/lib/active_record/associations/association.rb:221:in `raise_on_type_mismatch!' 
    from /Users/davea/.rvm/gems/[email protected]/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 ::關係

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

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

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

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

+0

我編輯了我的問題,以顯示當我嘗試您的建議時發生了什麼。只需添加「.take」?它不工作。 – Dave

+0

Nvm,它確實工作 - 數據被緩存,但是當我退出控制檯並重新加載時,它運行良好。 – Dave

0

有各種各樣的方式來獲得來自呼叫的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 
    
0

大多數ActiveRecord的方法,以提供一個流暢的API返回的ActiveRecord ::關係(語法賞心悅目的方法,如果你會鏈接)。我認爲這是一個設計決定。有幾種方法可以解決這個問題,如first(其實是find_nth!(0)的調用),lastto_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

可能是值得略讀通過。