以下代码来自Sinatra应用程序(使用DataMappe),我试图将其转换为Rails 3应用程序。它是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)")
答案 0 :(得分:2)
Model.connection.execute“你的SQL”应该可以帮到你。像
这样的东西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
答案 1 :(得分:1)
我知道你已经接受了答案,但是你要求最好的办法来做你在Rails中提出的问题。我提供这个答案是因为Rails不建议将building conditions作为纯查询字符串。
将自己的条件构建为纯字符串可能会使您容易受到SQL注入攻击。例如,
Client.where("first_name LIKE '%#{params[:first_name]}%'")
不安全。
幸运的是,Active Record非常强大,可以构建非常复杂的查询。例如,您可以使用四个方法调用重新创建查询,同时仍然易于阅读和安全。
# 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 Range转换为BETWEEN operator
或Array转换为IN expression
。
有关Active Record的详细信息,请查看the guide。它解释了Active Record的功能以及如何使用它。