基于标签等多对多关联的 RoR 搜索
我建立了一个包含几个不同模型的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
请记住,在 Rails 3 中,您可以执行比串联更不容易出错的链式查询,并且最好使用通配符来防止 SQL 注入。您可以将代码重构为类似于以下内容:
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: