简体   繁体   English

如何在Ruby中将ActiveRecord_Associations与数组合并

[英]How to merge ActiveRecord_Associations with Array in Ruby

I'm trying to merge a collection of Objects of type ActiveRecord_Associations with others objects in an array. 我正在尝试将ActiveRecord_Associations类型的对象的集合与数组中的其他对象合并。

Here is the piece of code that I'm working : 这是我正在工作的代码:

#Get all projects with the same tag of current project
related_projects = current_team.projects.select{
        |project| project.tag_group_id == current_project.tag_group_id && project.id != current_project.id }

#Get all relats of type release in the related projects
related_release_relats =  related_projects.flat_map{ |project| project.relats
        .find_all { |relat| relat.relat_type == 'release' } }

Is it possible to do something like that ? 可以做这样的事情吗?

I'm trying to merge the current project relats with the related_release_relats( this is all relats from the others projects related ) 我正在尝试将当前项目相关信息与related_release_relats合并(这是与其他相关项目相关的所有信息)

relats = current_project.relats
relats.merge(related_release_relats)

Thanks everyone 感谢大家

There's no merge method for arrays but you can add arrays together. 数组没有merge方法,但您可以将数组添加在一起。

current_project.relats + release_relats

If you want to ensure you don't include the same relats multiple times use uniq ... 如果要确保不多次包含相同的信息,请使用uniq ...

(current_project.relats + release_relats).uniq

If you want an ActiveRecord_Relation you can do... 如果您需要ActiveRecord_Relation ,可以执行...

Relat.where(id: (current_project.relats + release_relats).map(&:id))

Since I am not 100% clear on your database structure other than what I can glean from your post, I have made some assumptions here. 由于除了您可以从您的帖子中了解到的内容之外,我对您的数据库结构不是100%清楚,因此我在这里做了一些假设。

Given this structure 给定这种结构

 class Team < ApplicationRecord
    has_many :projects
 end

 class Project < ApplicationRecord
    belongs_to :team
    belongs_to :tag_group
    has_many :relats
 end

 class TagGroup < ApplicationRecord
    has_many :projects
 end

 class Relats < ApplicationRecord
    belongs_to :project
 end

We can build a few scopes (for convenience and re-usability) to put all this work on the database side of things 我们可以建立一些scopes (为了方便和可重用),将所有这些工作放在数据库方面

class Project < ApplicationRecord
    belongs_to :team
    belongs_to :tag_group
    has_many :relats
    # find projects related to a given project
    scope :related_to,->(project) do 
        # uses Rails 5 .not
        # alternative Rails < 5
        # where("tag_group_id =? and id != ?",project.tag_group_id, project.id)
        where(tag_group_id: project.tag_group_id).where.not(id: project.id)
    end
  end
end
class Relats < ApplicationRecord
    belongs_to :project
    # only Relats that are released
    scope :released,-> {where(relat_type: 'released')}
end

Then we will build a small service Object to consolidate this logic 然后,我们将构建一个小型服务对象以巩固这一逻辑

class RelatedRelatFinder
  def initialize(current_project,current_team)
    @current_project = current_project
    @current_team = current_team
  end

  # method to retrieve the current_project#relats and 
  # all the current_teams released relats related to the current_project
  def find_all_relats
    # uses Rails 5 .or
    # alternative Rails < 5
    # where("relats.id IN(?) OR relats.id IN(?)",
    #        @current_project.relats.to_sql,
    #        released_related_relats.to_sql)
    Relat.where(id: @current_project.relats)
        .or(Relat.where(id: released_related_relats))
  end

  private

  # This is the method for getting the current_teams released 
  # relats related to the current_project
    def released_related_relats
      Relat.released.merge(
          @current_team.projects.merge(
              Project.related_to(@current_project)
          )
      )
    end
end 

Then usage is as simple as: 然后用法很简单:

relat_finder = RelatedRelatFinder.new(current_project,current_team)
relat_finder.find_all_relats

and this will generate a SQL query similar to: 这将生成类似于以下内容的SQL查询:

SELECT relats.* 
FROM relats 
WHERE 
  (relats.id IN (
    SELECT relats.id 
    FROM relats 
    WHERE 
    relats.project_id = 1 #current_project.id
  ) OR 
  relats.id IN (
      SELECT relats.id 
      FROM relats 
      INNER JOIN projects ON projects.id = relats.project_id 
      WHERE 
        relats.relat_type = 'released' 
        AND projects.team_id = 1 #current_team.id
        AND projects.tag_group_id = 1 #current_project.tag_group_id
        AND (projects.id != 1) # not current_project.id
    )
  )

Which seems to be what you are asking for. 这似乎是您要的。 Now the code is more understandable, more organized, there are no intermediate Array being created and the Database is providing all the heavy lifting. 现在,代码更易于理解,更组织了,不再创建任何中间Array ,而数据库正在提供所有繁重的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM