Rails 4范围has_many

时间:2016-04-28 13:27:40

标签: ruby-on-rails ruby scope has-many

我有两个型号

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

class ProjectType < ActiveRecord::Base
  belongs_to :portfolio
end

ProjectType模型具有字段ptype。它可以是网络&#39;或者&#39; mobile&#39;等 我怎样才能获得所有网络&#39;或者&#39; mobile&#39;使用范围的投资组合?

4 个答案:

答案 0 :(得分:3)

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

# 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)

答案 1 :(得分:3)

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

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

我不推荐这个,我也不建议为每个&#34;字符串&#34; (例如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)

我认为这里或上面提到的这些解决方案中的任何一个都不再是&#34;正确&#34;,除了元编程解决方案为每个字符串生成一个范围存储在数据库中的ptype字段。

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

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

并且这样称呼:

 Portfolio.by_ptype(:web)

答案 2 :(得分:2)

你可以这样做

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')

答案 3 :(得分:1)

遵循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