Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@ pickle-email-*.html

# Ignore Byebug command history file.
.byebug_history

# Ignore Sphinx generadet config and database
/config/*.sphinx.conf
/db/sphinx
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ gem 'sidekiq'
gem 'sinatra', require: false
gem 'whenever'

gem 'mysql2' # Don't worry, it's for Sphinx only!
gem 'thinking-sphinx'

# gem 'unicorn'
gem 'thin'

Expand Down
17 changes: 16 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,12 @@ GEM
hashie (3.4.6)
http_parser.rb (0.6.0)
i18n (0.7.0)
innertube (1.1.0)
jbuilder (2.6.0)
activesupport (>= 3.0.0, < 5.1)
multi_json (~> 1.2)
joiner (0.3.4)
activerecord (>= 4.1.0)
jquery-rails (4.2.1)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
Expand Down Expand Up @@ -196,6 +199,7 @@ GEM
rack-contrib (~> 1.1)
railties (>= 3.0.0, < 5.1.0)
method_source (0.8.2)
middleware (0.1.0)
mime-types (3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
Expand All @@ -205,6 +209,7 @@ GEM
multi_json (1.12.1)
multi_xml (0.5.5)
multipart-post (2.0.0)
mysql2 (0.4.4)
nenv (0.3.0)
nokogiri (1.6.8)
mini_portile2 (~> 2.1.0)
Expand Down Expand Up @@ -238,7 +243,7 @@ GEM
orm_adapter (0.5.0)
parser (2.3.1.4)
ast (~> 2.2)
pg (0.18.4)
pg (0.19.0)
pkg-config (1.1.7)
powerpack (0.1.1)
private_pub (1.0.3)
Expand Down Expand Up @@ -309,6 +314,7 @@ GEM
require_all (1.3.3)
responders (2.3.0)
railties (>= 4.2.0, < 5.1)
riddle (1.5.12)
rspec (3.5.0)
rspec-core (~> 3.5.0)
rspec-expectations (~> 3.5.0)
Expand Down Expand Up @@ -391,6 +397,13 @@ GEM
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4)
rack (>= 1, < 3)
thinking-sphinx (3.2.0)
activerecord (>= 3.1.0)
builder (>= 2.1.2)
innertube (>= 1.0.2)
joiner (>= 0.2.0)
middleware (>= 0.1.0)
riddle (>= 1.5.11)
thor (0.19.1)
thread_safe (0.3.5)
tilt (2.0.5)
Expand Down Expand Up @@ -446,6 +459,7 @@ DEPENDENCIES
launchy
letter_opener
meta_request
mysql2
oj
oj_mimic_json
omniauth
Expand Down Expand Up @@ -477,6 +491,7 @@ DEPENDENCIES
sprockets (= 3.6.3)
test_after_commit
thin
thinking-sphinx
turbolinks
uglifier (>= 1.3.0)
web-console (~> 2.0)
Expand Down
7 changes: 7 additions & 0 deletions app/assets/stylesheets/search.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#global-search {
select {
border-radius:0;
border-left:none;
-webkit-appearance:none;
}
}
19 changes: 19 additions & 0 deletions app/controllers/search_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class SearchController < ApplicationController
before_filter :get_search_params

def search
@found = SearchService.search(type: @search_type, query: @search_query)
render :no_results if @found.empty?
end

private

def get_search_params
@search_query = params[:q]
@search_type = params[:t].to_s
unless @search_type.blank? || SearchService::ALLOWED_TYPES.include?(@search_type)
@search_type = nil
render nothing: true, status: :not_implemented
end
end
end
3 changes: 3 additions & 0 deletions app/indices/answers_index.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ThinkingSphinx::Index.define :answer, with: :active_record, delta: true do
indexes body
end
3 changes: 3 additions & 0 deletions app/indices/comments_index.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ThinkingSphinx::Index.define :comment, with: :active_record, delta: true do
indexes body
end
4 changes: 4 additions & 0 deletions app/indices/questions_index.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ThinkingSphinx::Index.define :question, with: :active_record, delta: true do
indexes topic, sortable: true
indexes body
end
3 changes: 3 additions & 0 deletions app/indices/users_index.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ThinkingSphinx::Index.define :user, with: :active_record, delta: true do
indexes email
end
2 changes: 2 additions & 0 deletions app/models/answer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class Answer < ActiveRecord::Base
validates :user_id, :question_id, presence: true
validates :body, presence: true, length: (20..50_000)

default_scope { order({starred: :desc}, :created_at) }

after_commit :invoke_subscriptions_delivery, on: :create

def star!
Expand Down
2 changes: 2 additions & 0 deletions app/models/attachment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ class Attachment < ActiveRecord::Base
mount_uploader :file, FileUploader

validates :file, presence: true

default_scope { order(:created_at) }
end
2 changes: 2 additions & 0 deletions app/models/comment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ class Comment < ActiveRecord::Base

validates :user_id, presence: true
validates :body, presence: true, length: (2..2_000)

default_scope { order(:created_at) }
end
2 changes: 2 additions & 0 deletions app/models/question.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class Question < ActiveRecord::Base
validates :topic, presence: true, length: (10..200)
validates :body, presence: true, length: (20..50_000)

default_scope { order(:created_at) }

after_create :subscribe_author!

private
Expand Down
17 changes: 17 additions & 0 deletions app/services/search_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class SearchService
ALLOWED_TYPES = %w(question answer comment user)

class << self
def search(params)
query = ThinkingSphinx::Query.escape(params[:query] || '')
type = params[:type] || ''
klass(type)&.search(query)
end

def klass(type)
return ThinkingSphinx if type == ''
return nil unless ALLOWED_TYPES.include?(type)
type.classify.constantize
end
end
end
2 changes: 1 addition & 1 deletion app/views/comments/_comment.slim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
p
p id="comment-#{comment.id}"
= comment.body
span.little style="color:gray"
'
Expand Down
7 changes: 7 additions & 0 deletions app/views/search/_answer.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
p
' Answer to the Question
i
= link_to "\"#{entry.question.topic}\"", entry.question
| :
p.lead
= link_to entry.body, question_path(entry.question, anchor: "answer-#{entry.id}")
13 changes: 13 additions & 0 deletions app/views/search/_comment.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
- commentable = entry.commentable
- question = commentable.kind_of?(Question) ? commentable : commentable.question
p
' Comment to the
=> commentable.class.name
i
- if commentable.kind_of?(Question)
= link_to "\"#{commentable.topic}\"", commentable
- else
= link_to "\"#{commentable.body}\"", question_path(question, anchor: "answer-#{commentable.id}")
| :
p.lead
= link_to entry.body, question_path(question, anchor: "comment-#{entry.id}")
4 changes: 4 additions & 0 deletions app/views/search/_question.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
p
' Question:
p.lead
= link_to entry.topic, entry
4 changes: 4 additions & 0 deletions app/views/search/_user.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
p
' User with email:
p.lead
= link_to entry.email, "mailto:#{entry.email}"
4 changes: 4 additions & 0 deletions app/views/search/no_results.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
h2 Search returns no results

.well style="margin-top:40px"
p We sorry but try to search with another query!
13 changes: 13 additions & 0 deletions app/views/search/search.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
h2 Search Results

h4 #{pluralize(@found.count, 'entry')} found:

- @found.each_with_index do |entry, cnt|
.well
.row
.col-xs-1
p.lead
= cnt + 1
| .
.col-xs-11
= render entry.class.name.downcase, entry: entry
13 changes: 10 additions & 3 deletions app/views/shared/_navbar.slim
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ nav.navbar.navbar-default role="navigation"
span.icon-bar
= link_to root_path, class: 'navbar-brand'
= image_tag 'logo.png', size: '24x24', alt: 'Deep Recursion', class: 'pull-left'
| &nbsp;&nbsp;Deep Recursion
| &nbsp;&nbsp;D/R
#navbar-collapse.collapse.navbar-collapse
ul.nav.navbar-nav
= navbar_item 'Questions List', questions_path
= navbar_item 'Questions', questions_path
- if policy(Question).new?
= navbar_item 'Ask a Question', new_question_path
- if current_user&.admin?
= navbar_item 'Applications', oauth_applications_path
= navbar_item 'Apps', oauth_applications_path
ul.nav.navbar-nav.navbar-right
li
- if user_signed_in?
Expand All @@ -27,3 +27,10 @@ nav.navbar.navbar-default role="navigation"
= navbar_item new_user_session_path
=> glyph 'log-in'
| Sign In
= form_tag search_path, method: :get, class: 'navbar-form navbar-right'
.form-group
.input-group#global-search
= search_field_tag :q, @search_query, class: 'form-control', size: 30, placeholder: 'Search for...'
span.input-group-btn
= select_tag :t, options_for_select({questions: :question, answers: :answer, comments: :comment, users: :user}, @search_type), prompt: 'anything ▾', class: 'form-control'
button.btn.btn-default type="submit" Go!
2 changes: 2 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

module DeepRecursion
class Application < Rails::Application
config.autoload_paths << Rails.root.join('services')

# Use the responders controller from the responders gem
config.app_generators.scaffold_controller :responders_controller

Expand Down
2 changes: 1 addition & 1 deletion config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
# access will be blocked just in the third day. Default is 0.days, meaning
# the user cannot access the website without confirming their account.
# config.allow_unconfirmed_access_for = 2.days
config.allow_unconfirmed_access_for = 2.days if Rails.env.test?
# config.allow_unconfirmed_access_for = 2.days if Rails.env.test?

# A period that the user is allowed to confirm their account before their
# token becomes invalid. For example, if set to 3.days, the user can confirm
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
devise_for :users, controllers: {omniauth_callbacks: :omniauth_callbacks}
match 'account/confirm_email', via: [:get, :patch]

get :search, to: 'search#search'

concern :rateable do
member do
post :rate_inc
Expand Down
4 changes: 4 additions & 0 deletions config/schedule.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
every 1.day, at: '9:00' do
runner 'MailDigestJob.perform_later'
end

every 1.hour, at: 42 do
rake 'ts:rebuild'
end
2 changes: 2 additions & 0 deletions config/thinking_sphinx.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test:
mysql41: 9307
8 changes: 8 additions & 0 deletions db/migrate/20160924001243_create_sphinx_deltas.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class CreateSphinxDeltas < ActiveRecord::Migration
def up
add_column :questions, :delta, :boolean, default: true, null: false
add_column :answers, :delta, :boolean, default: true, null: false
add_column :comments, :delta, :boolean, default: true, null: false
add_column :users, :delta, :boolean, default: true, null: false
end
end
Loading