2012-03-23 56 views
0

我的模型:检查负载SQL对象在Rails的

class User 
    has_many :items 
end 

class Item 
    belongs_to :user 

    def self.with_color(color, is_loaded) 
    if is_loaded 
     self.select { |i| i.color == color } 
    else 
     self.where(:color => color) 
    end 
    end 

end 

有我的控制器2种类型的代码。

## this line loads 'items' of the user and selects with the red color ## 
@colored_items = current_user.items.with_color('red', false) 

## this code should not load items twice ## 
@user_with_items = User.includes(:items).find(params[:user_id]) 
(...) 
colored_items = @user_with_items.with_color('red', true) 

如果我只写“选择”的版本,它不与1例如工作,和“地点”版本加载项再次即使它们已经加载。

如何检查对象是否已经加载?

回答

2

如何使用范围?

从例子摘自:

class Shirt < ActiveRecord::Base 
    scope :colored, lambda { |color| where(:color => color) } 
end 

更多阅读这里:http://apidock.com/rails/ActiveRecord/Scoping/Named/ClassMethods/scope

你的榜样,这应该是(未测试)

class User 
    has_many :items 
end 

class Item 
    belongs_to :user 
    scope :colored, lambda { |color| where(:color => color) } 
end 


## this line loads 'items' of the user and selects with the red color ## 
@colored_items = current_user.items.colored('red') 

## use of 'includes' here to solve (n+1) issue 
@user_with_items = User.includes(:items).find(params[:user_id]) 
colored_items = @user_with_items.colored('red') 

更新:

class User < ActiveRecord::Base 
    has_many :items 

    def colored_items(color) 
    self.items.to_a.select { |i| i.color == color } 
    end 
end 

user = User.includes(:items).find(1) 
    User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]] 
    Item Load (0.4ms) SELECT "items".* FROM "items" WHERE "items"."user_id" IN (1) 
=> #<User id: 1, name: nil, created_at: "2012-03-25 00:39:52", updated_at: "2012-03-25 00:39:52"> 
user.colored_items "red" 
=> [#<Item id: 1, color: "red", user_id: 1, created_at: "2012-03-25 00:41:00", updated_at: "2012-03-25 00:41:00">] 
user.colored_items "blue" 
=> [#<Item id: 2, color: "blue", user_id: 1, created_at: "2012-03-25 00:41:04", updated_at: "2012-03-25 00:41:04">] 

所以这里只有2个SQL。

+0

作用域与self.colored的方法相同。你的第一个例子运行良好,但第二个例子会执行另一个查询来只加载'红色'项目。我会做@ users_with_items.items.select {| e | e.color =='red'}而不是使用已经加载的对象的作用域。 – FancyDancy 2012-03-24 09:43:12

+0

好吧,你是对的。范围每次都在执行SQL。认为它会解决这个问题。可能是可以优化的东西。所以我已经为我的答案添加了一个可能的解决方案。 – Deradon 2012-03-25 00:50:18

+0

谢谢 - )。完全按照我的需要。 – FancyDancy 2012-03-25 10:44:50