2016-04-28 8 views
0

I持っている二つのモデル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ポートフォリオではなくprojectTypesのリストを返します – MaruniakS

答えて

2

があなたのモデルに適切な範囲を追加します。唯一のコントローラーに参加して、そのスコープを使用するタイプwebでポートフォリオをロードするには

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

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

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

私は私のp型フィールド列挙型を考慮し、これを書くとRailsの4.1のアプローチを以下に示します。

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

これはあなたを与える:p型に基づいてオブジェクトをフェッチする

ProjectType.web 
ProjectType.mobile 

スコープをしますが、

@projectType.web? 
@projectType.web! 

次のような便利な方法を教えてください。docs:http://api.rubyonrails.org/v4.1/classes/ActiveRecord/Enum.html

"web" Portfolioの取得方法を尋ねると、 "少なくとも、すべてのポートフォリオがptype 'Web'のProjectTypeを持っていると仮定します。

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

をし、ちょうど呼び出す:あなたはそれの外にスコープを作成することができ、最終的な改良ではhttp://apidock.com/rails/ActiveRecord/SpawnMethods/merge

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

は、ドキュメントを参照してください。

それから私は次のように書きます

Portfolio.web 
+0

enum値は整数でなければなりません。 –

+0

彼らはすることができますが、彼らはする必要はありません。私は、可読性の理由から文字列をデータベースの値として使用することを提案します。これは、新しいキーを追加したり、既存のキーを削除または並べ替える必要がある場合に備えて、さらに管理しやすくなります。 – coorasse

2

あなたは両方のための明示的なスコープを持つことができ、またはptypeに基づいて選択する1つのスコープを持つことも、データベース内の各固有のptypeのスコープをメタプログラムすることもできます。

ProjectType.ptype('web') 

または

:と呼ば

scope :ptype, -> (ptype) { where(ptype: ptype) } 

:あなたは異なる「のptype」の様々なを追加する場合、あなたはどんな「のptype」を処理するためにあなたの範囲を与える、次のいずれかを行うことができます

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') 
関連する問題