开发者

RoR Search based on many to many association such as tags

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
开发者_Python百科

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] )


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜