0

我正在尝试为 Article 类创建一个过滤器,该过滤器使用基于从 HTML 表单提交的参数动态构建的 SQL 查询。由于我有多个多对多关系,我不能使用 Article.where (我不认为反正)。虽然以下代码有效,但我不确定这是否是执行此查询的最有效方式以及它的安全性。我确实通过使用 ? 来防止 SQL 注入。sql 字符串中的关键字(一个 la Rails 约定),但想确保这已经足够了。关于如何使它更优雅的任何建议?

def self.filter(hash)
    hash.delete_if {|k,v| v == ""}
    hash[:writer_type] = (hash[:writer_type]) if hash[:writer_type] != nil
    sql_base = "select distinct articles.* from articles
       join tags
       on tags.article_id = articles.id
       join categories
       on tags.category_id = categories.id
       left outer join itineraries
       on itineraries.article_id = articles.id
       left outer join cities
       on itineraries.city_id = cities.id
       join users
       on users.id = articles.user_id"

    condition_array = []
    key_array = []
    hash.each_key {|key| key_array << key}
    key_array.each_with_index do |key, i|
      operator = "and"
      operator = "where" if i == 0
      case key
      when :writer
        sql_base << "\n#{operator} users.username like ?"
        condition_array << hash[:writer]
      when :writer_type
         sql_base << "\n#{operator} users.status in (?)"
        condition_array << hash[:writer_type]
      when :city
        sql_base << "\n#{operator} cities.name like ?" 
        condition_array << hash[:city]
      when :category
        sql_base << "\n#{operator} categories.name like ?"
        condition_array << hash[:category]
      end
    end
    sql_array = [sql_base,condition_array].flatten
    articles = Article.find_by_sql(sql_array)
    articles
  end
4

1 回答 1

1

当然,您应该能够执行以下操作:

q = Articles.join(:tags #, etc)

if condition
  q = q.joins(:user).where("users.status in ?", hash[:writer_type])
else
  q = q.joins(:cities).where("cities.name LIKE ?", hash[:city])
end

q

这是有效的,因为ActiveRecord::Relation仅在首次访问时执行查询。因此,在您调用to_a或枚举记录之前,您可以继续链接到对象。

如果你正在做复杂的查询,你可能想看看squeel它会让你重写你的条件,比如

q.where { users.status >> my { hash[:writer_type] } }

或者

q.where { cities.name =~ my { hash[:city] } }
于 2013-09-09T05:59:22.647 回答