Rails 4 个范围 has_many

Rails 4 scope has_many

我有两个模型

class Portfolio < ActiveRecord::Base
  has_many :project_types, dependent: :destroy
end

class ProjectType < ActiveRecord::Base
  belongs_to :portfolio
end

ProjectType 模型有字段 ptype。它可以是 'web' 或 'mobile' 等。 如何使用范围获取所有 'web' 或 'mobile' 投资组合?

按照 Rails 4.1 方法,我会将我的 ptype 字段视为一个枚举并写成:

class ProjectType < ActiveRecord::Base
   belongs_to :portfolio
   enum ptype: { web: 'web', mobile: 'mobile' }
end

这会给你:

ProjectType.web
ProjectType.mobile

基于 ptype 获取对象的范围,但也会为您提供其他有用的方法,例如:

@projectType.web?
@projectType.web!

请参考文档:http://api.rubyonrails.org/v4.1/classes/ActiveRecord/Enum.html

在这里您询问如何检索 "web" Portfolio 我假设您的意思是“所有项目类型至少为 ptype 'Web'.

然后我会这样写:

 Portfolio.joins(:project_types).merge(ProjectType.web)

查看文档:http://apidock.com/rails/ActiveRecord/SpawnMethods/merge

在最后的改进中,您可以从中创建一个范围:

class Portfolio
   has_many :project_types
   scope :web, -> { joins(:project_types).merge(ProjectType.web) }
end

然后只调用

Portfolio.web

为您的模型添加适当的范围:

# in models/project_type.rb
class ProjectType < ActiveRecord::Base
  belongs_to :portfolio

  scope :web, -> { where(ptype: 'web') }
end

要加载类型为 web 的投资组合,仅使用该范围与控制器中的连接:

# in the controller
@web_portfolios = Portfolio.joins(:project_types).merge(ProjectType.web)

您可以对两者都有明确的范围,或者您可以有一个范围根据 ptype 为您选择,或者您可以为数据库中的每个唯一 ptype 元编程一个范围。如果您要添加各种不同的 "ptypes",您可以执行以下任一操作,这将为您提供处理任何 "ptypes":

的范围
scope :ptype, -> (ptype) { where(ptype: ptype) }

称为:

ProjectType.ptype('web')

class ProjectType < ActiveRecord::Base
   self.pluck(:ptype).each do |ptype|
      scope ptype.gsub(/\s+/,"_").downcase.to_sym, -> { where(ptype: ptype) }
   end
end

我不推荐这个,我也不推荐其中的每个 "string"(例如 ProjectType.web 或 ProjectType.mobile)单独的范围。最好的平衡是将字符串值传递到一个范围内,该范围可检索您要查找的内容。只是我的意见,我相信其他人对此有不同的看法。

老实说,我认为 ptype 字段对于枚举器来说已经成熟了——这将使您的代码更加清晰,并定义该字段实际期望的内容,而不是允许将任何字符串随机放置在那里。所以像:

class ProjectType < ActiveRecord::Base
   enum ptype: [:web, :mobile]

   scope :ptype, -> (ptype) { where(ptype: self.ptypes[ptype] }
 end

然后这样调用:

ProjectType.ptype(:web)

我认为这里或上面介绍的这些解决方案中的任何一个都不再存在 "right",除了为存储在数据库中的 ptype 字段中的每个字符串生成范围的元编程解决方案。

最后,这是您的投资组合范围:

class Portfolio < ActiveRecord::Base
    scope :by_ptype, -> (ptype) { joins(:project_type).merge(ProjectType.ptype(ptype) }  
 end

然后这样调用:

 Portfolio.by_ptype(:web)

你可以这样做

class Portfolio < ActiveRecord::Base
  has_many :project_types, dependent: :destroy
  scope :ptype, -> (p_type) { includes(:project_types).where(project_types: {ptype: p_type}) }
end

你可以打电话给

Portfolio.ptype('web')