- Summary: real world white boarding, discussion among software developers, implementing an important feature - search feature - from a popular software suite - Basecamp product management software. Implementing one simple solution for the advanced feature. Showcase the thought, design and code process.
- Rating : 5 star, professional, concise, real-world coding experience, walks through the entire process
- Environment: Rails
- Step: first analyze the search feature and its behavior, then choose what to replicate. Basecamp dashboard search searches through entries, and makes suggestion of matching project messages and users. In case where no EXACT MATCH is found, the website does a FUZZY SEARCH, or a rough match instead.
- Step: analyze the data model. Simplified basecamp data model: project is the main object class, there are many projects, each can have many messages, each message has many comments. And there's the User model and user records. User can be associated with one or more projects.
- Step: create a search form with the search keyword input field. Method is GET.
- <%= form_tag search_path, method: :get do %>
- <%= text_field_tag 'keyword', nil %>
- <%= end %>
- Step: custom config search route. Not using any resources for this simple functionality.
- get 'search' => 'search#index', as: :search
- Step: Search Controller code using parameter input from the search field, first search by keyword in Project, then user and redirect correspondingly. Line 3 get the keyword. Line 5 doing the first exact match - project with the same title using Rails4 .find_by(). Redirect to the specific project with that title. Line 10: custom defined Search class with .for() method. Search is a custom Ruby class not an activerecord class. This is the line for a fuzzy search. Will return an array of concatenated
- Code: for Rails database %, the percentage sign, is the string wild card
|Sample code for implementing Basecamp search feature search controller|
Search projects by title, user by name or else do a fuzzy search
|Sample code for Basecamp fuzzy search feature implemented with Ruby on Rails|
Interview with David Heinemeier Hansson the famous creator of Ruby on Rails
- David explains:
- It's indeed okay to only use RESOURCES for CONTROLLER doing more complex task than just a single action.
- Resources is a macro script that will create a bunch of utilities for the controller.
- Opinion on Exact Match vs Fuzzy Match and how to scope:
- Best practice, David will not use local variables when possible. Ask the question What can it offer you? Does it make the code clearer? Change code : keyword = params[:keyword] to into inline local variable instead example
- code: if project = Projects.find_by(title: params[:keyword])
- It's a stylistic practice. Repeating hashlook up is okay, it's clear that the param is coming from outside world.
- Rather than using REDIRECT_TO multiple times create an instance method named with jump.
- Fuzzy search : Will have a hard time paginating the result from 3 tables. Cannot use offset properly since SQL offset is based on a single table.
- The search class in model has a def self.for(keyword), keyword seems to be internal but actually is from the "outside world" as it is a parameter. Need to be careful of SQL injection and hacking when utilizing user inputs. Because we are using the wild card in an unsanitized input, the hacker can pass in another percentage sign - another wild card sign. And if a friendly user searches for a % percentage sign, he can mess up the query too. Sanitization is needed.
- Basecamp uses ElasticSearch to handle its high volume, complex and practically all of its search features.
- If number of records is large, also need to manage the number of results. Consider ElasticSearch or an eternal search service. ElasticSearch is made to handle this multi-table query result situation too. It can index a variety of data and return the result for you. That's how basecamp does it. It uses ElasticSearch for almost everything.
- There's also a Ruby Gem for ElasticSearch.
|David Heinemeier Hansson extracts the .find_by and redirect_to methods on Projects and User into a|
jump target instance method.