使用模型搜索特定字段

时间:2016-03-12 22:04:57

标签: mysql ruby-on-rails ruby

所以我试图在模型中编写一个方法,允许我返回特定字段值大于0的帖子。

所以我的帖子中包含的字段基本上都是标签。基本上我发帖有四个字段,hiphop,electro,house和pop。每个字段的值介于0和10之间。

如果有人点击一个按钮,那么我就试图这样做。" Hip Hop"它将返回所有具有hiphop字段值大于0的帖子。

我知道这是错的,但我在想这样的事情

  def self.tagSearch(query)
    where("#{query} > 0")
  end

在我的控制器中我会有类似的东西

  def index
    if params[:search]
      @songs = Song.search(params[:search]).order("created_at DESC")
    elsif params[:tag]
      @songs = Songs.tagSearch(params[:tag]).order("created_at DESC")
    else
      @songs = Song.all
    end
  end

我不确定视图,但可能是一个传递标记值参数的按钮。问题是我只想把它当成一个按钮,我不需要它们输入任何东西。

我希望这不会让人感到困惑。

谢谢!

马特

2 个答案:

答案 0 :(得分:2)

Rails支持"范围"它返回一个ActiveRecord::Relation,这意味着你可以将它们链接在一起。

class Song
  scope :tag_search, -> (something) { where(something > 0) }
  scope :ordered, -> { order(created_at: :desc) }
end

class SongsController
  def index
    if params[:search]
      @songs = Song.search(params[:search]).ordered
    elsif params[:tag]
      @songs = Songs.tag_search(params[:tag]).ordered
    else
      @songs = Song.all
    end
  end
end

我会想到这个的设计。

另外,tagSearch功能非常危险。 SQL INJECTION!

答案 1 :(得分:2)

扩展RaVen帖子:

1)使用ruby命名约定tagSearch应为tag_search;方法是蛇形(带下划线的小写)。

2)where("#{query} > 0")让你暴露于SQL注入攻击 - 建议安装制动器gem,这可能会暴露出像这样的安全问题:

3)您可以通过链接范围来简化代码,返回nil的范围不会影响查询

class Song
  scope :search, -> (query) do 
    where("name LIKE ?", "#{query}%") if query.present?
  end

  scope :tag_search, -> (tag) do 
    where(tag > 0) if tag.present?
  end

  scope :ordered, -> do 
    order(created_at: :desc)
  end
end

class SongsController
  def index
    @songs = Song.search(params[:search])
               .tag_search(params[:tag])
               .ordered
  end
end

4)根据用户指定的列进行查询并避免sql注入:

这是一种方法,可能有其他更好的方法,比如使用模型arel_table,无论如何这个很直接

  scope :tag_search, -> (tag) do 
    where("#{self.white_list(tag)} > 0") if tag.present?
  end

  def self.white_list(column_name)
    # if the specified column_name matches a model attribute then return that attribute
    # otherwise return nil which will cause a sql error
    # but it won't let arbitrary sql execution
    self.attribute_names.detect { |attribute| attribute == column_name }
  end