基于标签等多对多关联的 RoR 搜索

发布于 2024-11-29 07:47:39 字数 3762 浏览 3 评论 0原文

我建立了一个包含几个不同模型的 RoR 数据库。每个“记录”都有许多标签,并且通过“cat_id”放入一个类别中。我已经构建了所有模型,但我需要过滤方面的帮助。现在,我可以从带有节点的树视图中选择一个类别,它会显示该类别和子类别中的所有记录。我还可以使用搜索功能(SQL 中的 LIKE 运算符)进行简单的文本搜索。我想添加一个额外的标签过滤器,以便能够选择类别和标签并显示结果。

这是我到目前为止所得到的:

RECORD MODEL

class AuctionRecord < ActiveRecord::Base

  #comments
  has_many :comments, :dependent => :destroy

  #tags
  has_many :auction_records_tags
  has_many :tags, :through => :auction_records_tags 

TAG MODEL

class Tag < ActiveRecord::Base
  attr_accessible :name
  has_many :auction_records_tags
  has_many :auction_records, :through => :auction_records_tags
end

AUCTIONS_RECORDS_TAGS MODEL

class AuctionRecordsTag < ActiveRecord::Base
  attr_accessible :auction_record_id, :tag_id

  belongs_to :tag
  belongs_to :auction_record

end

正如您所看到的,记录和标签具有多对多的关系,因此可以选择许多标签并返回许多拍卖记录。

记录控制器

@auction_records = AuctionRecord.filter(session[:search], @cat_sql).order(sort_column + " " + sort_direction).paginate(:per_page => 20, :page => session[:page] )

过滤功能

 #this is the main search engine
        def self.filter(search, cat_sql)   

        search_sql = "" 

        if search != ""  
          search_sql = "title LIKE '%#{search}%' OR itemnumber LIKE '%#{search}%' OR buyer LIKE '%#{search}%' OR seller LIKE '%#{search}%'"
          end

        if cat_sql != "" && search == ""
          search_sql = cat_sql
        end    

        if cat_sql != "" && search != ""
          search_sql = search_sql + " AND " + cat_sql
        end

        if search_sql !=""      
          where(search_sql)
        else 
          scoped
        end

      end

我通过循环遍历所有节点和子节点来手动生成类别sql语句。正如你所看到的,我几乎所有的事情都是“手动”完成的(不是最好的方法)。事实上,某些过滤器也可能未定义,这很麻烦(例如类别选择,但没有搜索词)。我认为所有三个过滤器都可以在一行代码中完成,但我不确定它是如何完成的。也许类似tags.auction_records?如果我需要发布表的架构,我也可以这样做,但目前所有分类和标记都是通过整数/id 关系完成的。

提前感谢任何帮助/评论

最好的问候

添加信息#1

节点模型(用于分类/类别)

class Node < ActiveRecord::Base
  has_many :nodes
  belongs_to :node
end

架构

 create_table "auction_records", :force => true do |t|
    t.string   "title"    
    t.string   "categorization"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

 create_table "auction_records_tags", :force => true do |t|
    t.integer  "auction_record_id"
    t.integer  "tag_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "nodes", :force => true do |t|
    t.integer  "node_id"
    t.string   "text"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "tags", :force => true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

对于“auction_records”,字段分类包含指向其所属节点的node_id 整数到树视图上。如果单击单个节点(类别),则会出现许多拍卖记录。 auction_records_tags 还创建 auction_records 和标签之间的关联。我发现了一些只适用于一个 tag_id 的东西,但我必须为多个标签做一些事情。

现在我有这段代码,它返回错误“未找到名为“节点”的关联”

       search_term = session[:search]
        term = "%#{search_term}%"
        @auction_records = AuctionRecord.scoped
        @auction_records = @auction_records.where('title LIKE ?', term).where('description LIKE ?',term)  if search_term
        @auction_records = @auction_records.joins(:nodes).where('node.node_id IN ?', session[:cat_id])  if session[:cat_id]
            @auction_records = @auction_records.joins(:tags).where('tags.id = ?', session[:tag_ids])  if session[:tag_ids]
        @auction_records = @auction_records.order(sort_column + " " + sort_direction).paginate(:per_page => 20, :page => session[:page] )

I have built a RoR database with several different models. Each "record" has many taggings and also is put into a category by a "cat_id." I have built all the models, but I need help with filtering. Right now I have the ability to select a category from a tree view with nodes and it shows all the records in that category and children categories. I can also do a simple text search with a search function (LIKE operator in SQL). I want to add an additional filter of tags to be able to select a category and a tag and show the results.

Here's what I've got so far:

RECORD MODEL

class AuctionRecord < ActiveRecord::Base

  #comments
  has_many :comments, :dependent => :destroy

  #tags
  has_many :auction_records_tags
  has_many :tags, :through => :auction_records_tags 

TAG MODEL

class Tag < ActiveRecord::Base
  attr_accessible :name
  has_many :auction_records_tags
  has_many :auction_records, :through => :auction_records_tags
end

AUCTIONS_RECORDS_TAGS MODEL

class AuctionRecordsTag < ActiveRecord::Base
  attr_accessible :auction_record_id, :tag_id

  belongs_to :tag
  belongs_to :auction_record

end

As you can see the records and tags have a many to many relationship so it is possible to select many tags and be returned with many auction records.

RECORD CONTROLLER

@auction_records = AuctionRecord.filter(session[:search], @cat_sql).order(sort_column + " " + sort_direction).paginate(:per_page => 20, :page => session[:page] )

FILTER FUNCTION

 #this is the main search engine
        def self.filter(search, cat_sql)   

        search_sql = "" 

        if search != ""  
          search_sql = "title LIKE '%#{search}%' OR itemnumber LIKE '%#{search}%' OR buyer LIKE '%#{search}%' OR seller LIKE '%#{search}%'"
          end

        if cat_sql != "" && search == ""
          search_sql = cat_sql
        end    

        if cat_sql != "" && search != ""
          search_sql = search_sql + " AND " + cat_sql
        end

        if search_sql !=""      
          where(search_sql)
        else 
          scoped
        end

      end

I generate the category sql statement manually by for looping through all the nodes and children nodes. As you can see I do almost everything "manually" (not the best way). The fact that certain filters may also not be defined was troublesome (for example a category selection, but no search term). I think all three filters can be accomplished in one line of code, but I'm not sure how it's done. Perhaps something like tags.auction_records? If I need to post the schema of the tables, I can do that too, but for now all the categorization and taggings are done with integer/id relationships.

Thanks in advance for any help / comments

Best regards

Added Info #1

NODE MODEL (used for categorization/categories)

class Node < ActiveRecord::Base
  has_many :nodes
  belongs_to :node
end

SCHEMA

 create_table "auction_records", :force => true do |t|
    t.string   "title"    
    t.string   "categorization"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

 create_table "auction_records_tags", :force => true do |t|
    t.integer  "auction_record_id"
    t.integer  "tag_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "nodes", :force => true do |t|
    t.integer  "node_id"
    t.string   "text"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "tags", :force => true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

For "auction_records", the field categorization contains the node_id integer to point to which node it belongs to on the tree view. If you click on a single node (category), many auction_records appear. The auction_records_tags also creates the association between auction_records and tags. I have found something that works for only one tag_id, but I will have to work on something for multiple tags.

Right now I have this code and it is returning the error "Association named "nodes" was not found"

       search_term = session[:search]
        term = "%#{search_term}%"
        @auction_records = AuctionRecord.scoped
        @auction_records = @auction_records.where('title LIKE ?', term).where('description LIKE ?',term)  if search_term
        @auction_records = @auction_records.joins(:nodes).where('node.node_id IN ?', session[:cat_id])  if session[:cat_id]
            @auction_records = @auction_records.joins(:tags).where('tags.id = ?', session[:tag_ids])  if session[:tag_ids]
        @auction_records = @auction_records.order(sort_column + " " + sort_direction).paginate(:per_page => 20, :page => session[:page] )

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦归所梦 2024-12-06 07:47:39

请记住,在 Rails 3 中,您可以执行比串联更不容易出错的链式查询,并且最好使用通配符来防止 SQL 注入。您可以将代码重构为类似于以下内容:

def self.filter(search_term, categories, tags)
  term = "%#{search_term}%"
  auction_records = AuctionRecord.scoped
  auction_records = auction_records.where('title LIKE ?', term).where('other_field LIKE ?',term)  if search_term
  auction_records = auction_records.joins(:categories).where('categories.name IN ?', categories)  if categories
  auction_records = auction_records.joins(:tags).where('tags.name IN ?' tags)  if tags
end

Remember that in Rails 3 you can do chained queries that are less error prone than concatenation, also is better to use wildcards to prevent SQL injection. You can refactor the code to look similar to this:

def self.filter(search_term, categories, tags)
  term = "%#{search_term}%"
  auction_records = AuctionRecord.scoped
  auction_records = auction_records.where('title LIKE ?', term).where('other_field LIKE ?',term)  if search_term
  auction_records = auction_records.joins(:categories).where('categories.name IN ?', categories)  if categories
  auction_records = auction_records.joins(:tags).where('tags.name IN ?' tags)  if tags
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文