2011-09-21 33 views
1

是否可以根據其屬性之一檢索has_many關聯中的子元素爲散列?根據子屬性檢索has_many關聯作爲散列

例如,假設具有用於每一天的單個盤的菜單:

class Menu 
    has_many :dishes 
end 

class Dish 
    belongs_to :menu 
end 

Dish有一個鍵,day,這是任一mondaytuesday等一個。是否有某種方法可以設置has_many關聯,以便Menu.dishes返回類似於{:monday => 'spaghetti', :tuesday => 'tofu', ... }的哈希?

回答

3

當然。像這樣的東西應該足夠了(假設例如「意大利麪條」被存儲在名爲food的列中)。

class Dish 
    belongs_to :menu 

    scope :by_day { select [ :day, :food ] } 

    def self.by_day_hash 
    by_day.all.reduce({}) {|hsh,dish| hsh[dish.day] = dish.food; hsh } 
    end 
end 

class Menu 
    has_many :dishes 

    def dishes_by_day 
    dishes.by_day_hash 
    end 
end 

# Usage 
m = Menu.where(...) 
m.dishes_by_day #=> { "monday" => "Spaghetti", "tuesday" => "Tofu" } 

所以這裏發生了什麼的是,在Dishby_day範圍返回只有兩列,dayfood。但是,它仍然返回Dish對象而不是哈希(因爲這是範圍),所以我們定義了一個類方法by_day_hash,它將結果轉換爲哈希。

然後在Menu我們定義dishes_by_day,它只是調用我們上面關於關聯的方法。您可以將這個dishes稱爲,但我認爲最好保留原始關聯的名稱,因爲您可能以後需要將其用於其他事情。

順便(以下可選的東西,暫時跳過,如果你的眼睛已經呆滯),我可能會by_day_hash這樣,而不是:

class Dish 
    belongs_to :menu 

    scope :by_day { select [ :day, :hash ] } 

    def to_s 
    food 
    end 

    def by_day_hash 
    hsh = HashWithIndifferentAccess.new 
    by_day.reduce(hsh) {|hsh, dish| hsh[dish.day] = dish } 
    end 
end 

# Usage 
m = Menu.where(...) 
m.dishes_by_day #=> { "monday" => #<Dish food: "Spaghetti", ...>, "tuesday" => #<Dish food: "Tofu", ...>, ... } 

...這樣你仍然得到完整的當你打電話給對象時,例如:Dishby_day_hash["monday"],但to_s方法意味着您可以將其放到像<%= @menu.dishes_by_day["monday"] %>這樣的視圖中,並獲得「意大利麪條」而不是#<Dish day: "monday", food: "Spaghetti">

最後,您可能還注意到我使用了HashWithIndifferentAccess.new而不是{}(哈希)。 HashWithIndifferentAccess是一個由Rails提供(並在任何地方使用)的類,它與Hash相同,但可以讓你做例如some_hash["monday"]some_hash[:monday]並得到相同的結果。完全可選,但非常方便。

+0

不錯,謝謝!仍然讓我的頭腦圍繞着所有可以用Ruby和Rails做的很酷的小東西。 – Russell

+0

很高興能幫到您,@Russell。 ActiveRecord指南(http://guides.rubyonrails.org/active_record_querying.html)是一個非常有用的指南,它不會在每週或每兩週閱讀完整內容。 ;)P.S.我注意到我在'scope:by_day'中省略了':'。你會想要介意的! –

+0

'by_day_hash'應該返回'hsh',以便按預期工作。 – pgb

0

這裏是一個很好的方式做到這一點在現代ActiveRecords和RUBYS:

# In class Menu 
def foods_by_day 
    Hash[ dishes.pluck(:day, :food) ] 
end 

dishes.pluck(:day, :food)返回類似[ ['monday', 'spaghetti'], ['tuesday', 'tofu], ... ]數組; Hash[]將該陣列數組轉換爲散列。

相關問題