4

私は条件付き連鎖を実装しようとしました、そしてこれは私が得たものです:

コントローラインデックスアクションコード:

@range_start = params[:range_start]
@range_stop = params[:range_stop]
Contract.within_range(@range_start, @range_stop)

モデルコード:

def self.within_range(range_start = Date.today - 1.month, range_stop = nil)
  self.started_after(range_start).started_before(range_stop)
end

def self.started_after(range_start)
  if range_start.blank?
    self
  else
    self.where('start_date >=?', range_start)
  end
end

def self.started_before(range_stop)
  if range_stop.blank?
    self
  else
    self.where('start_date<=?', range_stop)
  end
end

動作しますが、見栄えがよくありません。を使って少し改善しようとしましたがtap、成功しませんでした。このコードをどのように改善できますか?

更新:Inはインライン条件付きに変換できますが、何か他のものを改善できる可能性がありますか?

range_start.blank? ? self : self.where('start_date >=?', range_start)

UPDATE2:range_stopが設定されていない場合、このコードは実際には機能せず、started_after条件は適用されません。

started_before最初の状態を緩めないために私は何から戻らなければなりませんか?

4

4 に答える 4

10

時間が経過し、denis.peplinのソリューションはすでに非推奨になっています。そうでなければ、それは正しいです、あなたは連鎖のための関係が必要です。したがって、使用する代わりに、次のように使用scopedする必要がありますall

def self.started_before(range_stop)
  if range_stop.blank?
    all
  else
    where('start_date<=?', range_stop)
  end
end

しかし、これをより簡潔にするためのスコープとして書くこともできます。

scope :started_before, ->(range_stop){ range_stop.blank? ? all : where('start_date<=?', range_stop) }
于 2014-01-21T12:06:08.583 に答える
3

ルビーの世界には、scopeあなたが望むことをするというものがあります。

scope :started_after, lambda {|x| where("start_date >=?", x) }
scope :started_before, lambda{|x| where("start_date <=?", x) }

または一行で

scope :starts_between, lambda{|start,finish| where("start_date >=? AND start_date <= ?", start, finish) }

スコープはアクティブな記録機能であるため、次のように呼び出すことができます。

Contract.starts_between(date1, date2)

2番目のパラメーターを条件付きにする場合:

def self.within_range(start, finish = nil)
  data = Contract.started_after(start)
  data = data.started_before(finish) unless finish.nil?
  data
end
于 2012-10-16T08:49:32.927 に答える
3

このように条件付き連鎖を行う目的を明確にしたいと思います。つまり、メソッド内の条件を非表示にし、メソッドを連鎖させることで、結果のメソッドは単純になります。

可能ですが、ActiveRecord::Baseクラスの子をそれ自体でチェーンすることはできません。関係のみを連鎖させることができます。

したがって、これを行う代わりに:

def self.started_before(range_stop)
  if range_stop.blank?
    self
  else
    self.where('start_date<=?', range_stop)
  end
end

これを行う必要があります:

def self.started_before(range_stop)
  if range_stop.blank?
    scoped
  else
    self.where('start_date<=?', range_stop)
  end
end

1つの変更のみ:selfがに置き換えられscoped、メソッドは常にスコープを返し、チェーンできるようになりました。

ヒントについては、この記事に感謝します:http: //blog.mitchcrowe.com/blog/2012/04/14/10-most-underused-activerecord-relation-methods/

于 2012-11-08T16:33:44.767 に答える
1

私はこれを追加しました:

scope :dynamic, -> (chain=nil) { chain.present? ? chain.call : nil }

そして今、あなたはそれをこのように使うことができます

conditional_scope = x ? Model.scope1 : Model.scope2
Model.scope3.dynamic(conditional_scope).scope4
于 2015-05-13T16:39:42.090 に答える