是否可以根据其中一个属性将has_many
关联中的子元素检索到哈希中?
例如,想象一下每天都有一道菜的菜单:
class Menu
has_many :dishes
end
和
class Dish
belongs_to :menu
end
Dish
有一个密钥day
,它是monday
,tuesday
等之一。是否有某种方法可以设置has_many
关联这样Menu.dishes
会返回类似于{:monday => 'spaghetti', :tuesday => 'tofu', ... }
的哈希值?
答案 0 :(得分:5)
不确定。这样的东西应该足够了(假设例如“意大利面条”存储在名为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" }
所以这里发生的事情是Dish
by_day
范围只返回两列,day
和food
。但是,它仍然返回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", ...>, ... }
...这样,当您拨打电话时,您仍会获得完整的Dish
个对象by_day_hash["monday"]
但to_s
方法意味着您可以将其放入<%= @menu.dishes_by_day["monday"] %>
之类的视图中,然后获取“Spaghetti”而不是#<Dish day: "monday", food: "Spaghetti">
。
最后,您可能还会注意到我使用了HashWithIndifferentAccess.new
而不是{}
(哈希)。 HashWithIndifferentAccess是一个由Rails提供(并在任何地方使用)的类,它与Hash相同但允许你做任何一个例如some_hash["monday"]
或some_hash[:monday]
并获得相同的结果。完全可选,但非常方便。
答案 1 :(得分: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[]
将该数组数组转换为哈希值。