我如何在我的"包括"中指定条件?我的Rails查询的子句?

时间:2017-03-03 21:59:15

标签: ruby-on-rails activerecord model include ruby-on-rails-5

我使用Rails 5.我有这个模型

class MyObjectTime < ActiveRecord::Base
    ...
  has_many :user_my_object_time_matches

然后在我的控制器中我有这个用于查询某些模型

  @results = MyObjectTime.joins(:race,
                            "LEFT JOIN user_my_object_time_matches on my_object_times.id = user_my_object_time_matches.my_object_time_id #{additional_left_join_clause}")
                     .where( search_criteria.join(' and '), *search_values )
                     .limit(1000) 
                     .order("my_objects.day DESC, my_objects.name")
                     .paginate(:page => params[:page])
                     .includes(:user_my_object_time_matches)

我的问题是,虽然我希望返回所有MyObjectTime对象,但根据某些条件,我不想要所有的&#34; user_my_object_time_objects&#34;附加到每个模型的只有满足某些标准的标准(例如,其user_my_object_time_match.user_id字段为空或等于&#34; 30&#34;的那些标准)。如何指定标准以仅强制为每个MyObjectTime模型包含某些user_my_object_time_matches?

1 个答案:

答案 0 :(得分:0)

包含用于预先加载,因此我假设您需要加载MyObjectTime个记录以及user_my_object_time_matches个关联,因此您不必再查询数据库。

包含工作的方式是:

MyObjectTime.where(search_criteria.join(' and '))includes(:user_my_object_time_matches)

那将查询数据库两次:

  • 根据search_criteria

    加载所有MyObjectTime记录
    SELECT * FROM my_object_times WHERE (....)
    
  • 加载所有关联的UserMyObjectTimeMachine条记录

    SELECT * FROM user_my_object_time_machines WHERE my_object_time_id IN ( [ids returned by the previous query ])
    

因此,如果您想在第二个查询中添加其他过滤,那么在模型MyObjectTime中您可以添加另一个关联:

class MyObjectTime < ActiveRecord::Base
  ...
  has_many :user_my_object_time_matches
  has_many :user_my_object_time_matches_with_null_user, -> { where("user_id IS NULL or user_id = 30") }, class_name: "UserMyObjectMatch"

然后当你打电话

MyObjectTime.where(search_criteria.join(' and ')).includes(:user_my_object_time_matches_with_null_user)

第二个查询将如下所示:

SELECT * FROM user_my_object_time_machines WHERE (user_id IS NULL OR user_id = 30) AND my_object_time_id IN ( [ids returned by the previous query ])

这样你的例子就像这样:

@results = MyObjectTime.joins(:race)
                       .where( search_criteria.join(' and '), *search_values )
                       .limit(1000) 
                       .order("my_objects.day DESC, my_objects.name")
                       .paginate(:page => params[:page])
                       .includes(:user_my_object_time_matches_with_null_user)

没有急切加载

如果每次条件不一样(user_id IS NULL或user_id = 30),那么我不知道一个好的方法来急切加载所有东西。所以你可以使用普通的左连接,但是当你试图获取关联记录时会执行查询:

 @results = MyObjectTime.joins(:race,
                            "LEFT JOIN user_my_object_time_matches on my_object_times.id = user_my_object_time_matches.my_object_time_id AND (user_my_object_time_matches.user_id IS NULL or user_my_object_time_matches.user_id = 30)")
                     .where( search_criteria.join(' and '), *search_values )
                     .limit(1000) 
                     .order("my_objects.day DESC, my_objects.name")
                     .paginate(:page => params[:page])
                     .includes(:user_my_object_time_matches)

您可以在渴望加载关联中找到大量文档:

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html