2016-04-28 2 views
0

У меня есть две моделиRails 4 сферы применения has_many

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

class ProjectType < ActiveRecord::Base 
    belongs_to :portfolio 
end 

ProjectType модель имеет поле ptype. Это может быть «веб» или «мобильный» и т. Д. Как я могу получить все «сетевые» или «мобильные» портфолио с помощью областей?

+2

Как 'scope: web, -> {где (ptype: 'web')}'? – Stefan

+0

@Stefan будет возвращать список типов проектов, а не портфолио – MaruniakS

ответ

2

Добавить соответствующий простор для вашей модели:

# 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

После 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, и я предполагаю, что вы имеете в виду «Все портфолио с хотя бы ProjectType 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 
+0

Ваши значения перечисления должны быть целыми числами. –

+0

они могут, но им этого не нужно. Я бы предложил использовать строки в качестве значений в базе данных для удобства чтения. Это также намного более управляемо, если вам нужно добавить новые ключи или удалить или изменить порядок существующих. – coorasse

2

Вы можете иметь явные области для обоих, или у вас может быть одна область, которая выбирает для вас на основе 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 

Я не рекомендую это, и я также не рекомендую отдельные области для каждой «строки» (например, 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) 

Я не думаю, что какой-либо один из этих решений, представленных здесь, или выше, больше «вправо», за исключением решения мета-программирования это создает область для каждой строки в поле ptype, хранящемся в базе данных.

Наконец, здесь есть простор для Вашего портфолио:

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

И называется так:

Portfolio.by_ptype(:web) 
+0

Очень тщательно! – zgood

+0

@zgood Кто наблюдает за стражами? –

1

Вы можете сделать это таким образом

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