【问题标题】:How can I get some model's objects and its associated model's objects conditionally through an intermediary model object, using ActiveRecord如何使用 ActiveRecord 通过中间模型对象有条件地获取某些模型的对象及其关联模型的对象
【发布时间】:2011-01-19 02:15:44
【问题描述】:

如何通过中间模型对象有条件地获取某些模型的对象及其关联模型的对象?然后这将用于生成 JSON(通过to_json)。

下面是更通用的设置:

class JobSet < ActiveRecord::Base
  belongs_to :job_system
  has_many :resources, through => :job_system
  has_many :jobs
  ...
end

class JobSystem < ActiveRecord::Base
  has_many :job_sets
  has_many :resources
  ...
end

class Resource < ActiveRecord::Base
  belongs_to :job_system
  has_many_and_belongs_to_many :jobs
  ...
end

class Job < ActiveRecord::Base
  belongs_to :job_system
  belongs_to :job_set
  has_many_and_belongs_to_many :resources
  ...
end

我想要做的是获取所有资源及其对应的作业,但只获取属于特定作业集的作业。

更新:即使一个资源没有与之关联的任何工作,我仍然希望将它与其余资源一起获取。目的是显示所有资源以及分配给它们的任何作业。

看起来我可以在使用through 时设置conditions,但是当它是我所追求的下一个对象关联时,我似乎无法弄清楚如何做到这一点......

这类问题有好听的名字吗?有什么简单的方法可以做到这一点?

更新 2:似乎有一些解决方案在控制器中运行良好,但我在视图中使用 to_json 来预加载画布元素。当我这样做时,它似乎会自动包含所有工作:

var resources = <%= @resources.to_json(:include => {:jobs => {:only => :id}}) %>; 

手动 SQL JOIN 甚至会对此有所帮助吗?

【问题讨论】:

    标签: ruby-on-rails json activerecord associations has-many-through


    【解决方案1】:

    我想我知道你在追求什么。我唯一要问的是,如果某个资源在此特定作业集中没有任何作业,是否仍应包括在内?

    无论如何,这是一种方法:

    @resources = Resource.all(:include => :jobs,
                              :conditions => ["jobs.job_set_id = ?", @job_set.id])
    

    这将不包括没有与@job_set 关联的作业的资源

    那么,我的假设是否完全错误,或者这就是你之后的结果?

    编辑

    好吧,这比我想象的要难。有几种解决方案,但没有一个是我真正喜欢的。你可以这样做:

    @resources = Resource.all
    
    @resources.each do |resource|
      resource.jobs.all(:conditions => ["jobs.job_set_id = ?", @job_set_id])
    end
    

    但这会导致 1+n 查询次数问题对您的数据库造成压力。

    你也可以这样做:

    @resources = Resource.all(:include => :jobs)
    
    @resources.each do |resource|
      resource.jobs.select{ |job| job.job_set_id == @job_set_id }
    end
    

    但这会导致服务器端消耗更多的内存,因为所有作业都是急切加载的,然后循环查看哪个与 job_set_id 匹配。

    在我看来,找到更好解决方案的问题在于,这应该在 SQL JOIN 条件中指定,但我认为 ActiveRecord 不允许我们结合预先加载来修改它。

    【讨论】:

    • 是的,我们希望包括所有资源,即使是那些没有工作的资源。显示的是所有资源及其分配给它们的作业的列表(即使没有)。谢谢!
    • 嗯,没那么容易...我做了更新,但我不知道是不是你想要的
    • 嗯,这似乎在控制器中运行良好,但我在视图中使用 to_json 来预加载画布元素。它似乎自动包含所有这样的作业: var resources = {:reservations => {:only => :id}}) %>;手动 SQL JOIN 甚至会对此有所帮助吗?感谢大家的帮助!
    • 对不起,我的意思是 :jobs 不是 :reservations 以上。大脑中的食物!
    【解决方案2】:

    您应该能够以非常直接的方式执行此操作,但您可能需要特定格式或结构的集合,而不是此处给出的:

    @resources = @job_set.resources.include(:jobs)
    

    作为说明,我建议不要使用 Rails 1 样式的 has_many_and_belongs_to_many 声明。与更现代的连接模型方法相比,他们使用的连接表不是基于模型的,并且非常难以操作,尤其是当它们具有与之关联的元数据时。您只需创建一个名为 JobResource 或 ResourceJob 的模型,具体取决于您希望如何确定事物的优先级,并建立两个 belongs_to 关系将它们连接在一起。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-03
      • 2018-05-15
      • 2015-10-19
      • 2014-01-13
      • 1970-01-01
      • 2020-10-03
      • 1970-01-01
      • 2022-12-01
      相关资源
      最近更新 更多