2

以下のコードは、Rails 3アプリケーションに変換しようとしているSinatraアプリ(DataMappeを使用)からのものです。これは、Visitクラスのクラスメソッドです。

def self.count_by_date_with(identifier,num_of_days)
    visits = repository(:default).adapter.query("SELECT date(created_at) as date, count(*) as count FROM visits where link_identifier = '#{identifier}' and created_at between CURRENT_DATE-#{num_of_days} and CURRENT_DATE+1 group by date(created_at)")
    dates = (Date.today-num_of_days..Date.today)
    results = {}
    dates.each { |date|
      visits.each { |visit| results[date] = visit.count if visit.date == date }
      results[date] = 0 unless results[date]
    }
    results.sort.reverse    
  end

私の問題はこの部分にあります

 visits = repository(:default).adapter.query("SELECT date(created_at) as date, count(*) as count FROM visits where link_identifier = '#{identifier}' and created_at between CURRENT_DATE-#{num_of_days} and CURRENT_DATE+1 group by date(created_at)")

Rails(私が知る限り)にはこのリポジトリメソッドがなく、クエリが次のようなオブジェクトで呼び出されることを期待しています。Visit.find

Railsアプリ用にこれをどのように書くのが最適かというヒントを誰かに教えてもらえますか?

私はすべきですか

Visit.find_by_sql("SELECT date(created_at) as date, count(*) as count FROM visits where link_identifier = '#{identifier}' and created_at between CURRENT_DATE-#{num_of_days} and CURRENT_DATE+1 group by date(created_at)")
4

2 に答える 2

2

Model.connection.execute「YOURSQL」が役に立ちます。何かのようなもの

class Visit < Activerecord::Base

   class << self
    def trigger(created_at,identifier,num_of_days) 
    sql =  "SELECT date(created_at) as date, count(*) as count FROM visits where  link_identifier = '#{identifier}' and created_at between CURRENT_DATE-#{num_of_days} and CURRENT_DATE+1 group by date(created_at)"

    connection.execute sql   
    end
   end
  end 
于 2012-09-10T03:10:03.013 に答える
1

あなたはすでに答えを受け入れていることを知っていますが、Railsで求めたことを実行するための最良の方法を求めました。Railsは純粋なクエリ文字列として条件を構築することを推奨していないため、この回答を提供します。

純粋な文字列として独自の条件を構築すると、SQLインジェクションのエクスプロイトに対して脆弱になる可能性があります。たとえば、Client.where("first_name LIKE '%#{params[:first_name]}%'")安全ではありません。

幸い、Active Recordは非常に強力で、非常に複雑なクエリを作成できます。たとえば、クエリは4つのメソッド呼び出しで再作成できますが、読みやすく安全です。

# will return a hash with the structure
# {"__DATE__" => __COUNT__, ...}
def self.count_by_date_with(identifier, num_of_days)
  where("link_identifier = ?", identifier)
  .where(:created_at => (num_of_days.to_i.days.ago)..(1.day.from_now))
  .group('date(created_at)')
  .count
end

Active Recordは、Rubyオブジェクトを有効なSQLセレクターおよびオペレーターに変換するために構築されています。これを非常にクールなものにしているのは、RailsがRuby範囲をに、BETWEEN operatorまたは配列をに変換できることIN expressionです。

Active Recordの詳細については、ガイドをご覧ください。ActiveRecordの機能とその使用方法について説明します。

于 2012-09-10T04:24:00.057 に答える