| @@ -2,6 +2,7 @@ source 'https://rubygems.org' | |||||
| gem 'paperclip', '~> 5.0.0' | gem 'paperclip', '~> 5.0.0' | ||||
| gem 'docsplit', '~> 0.7.6' | gem 'docsplit', '~> 0.7.6' | ||||
| gem 'filewatcher', '~> 0.5.3' | |||||
| # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' | ||||
| gem 'rails', '~> 5.0.0', '>= 5.0.0.1' | gem 'rails', '~> 5.0.0', '>= 5.0.0.1' | ||||
| @@ -59,6 +59,8 @@ GEM | |||||
| erubis (2.7.0) | erubis (2.7.0) | ||||
| execjs (2.7.0) | execjs (2.7.0) | ||||
| ffi (1.9.14) | ffi (1.9.14) | ||||
| filewatcher (0.5.3) | |||||
| trollop (~> 2.0) | |||||
| globalid (0.3.7) | globalid (0.3.7) | ||||
| activesupport (>= 4.1.0) | activesupport (>= 4.1.0) | ||||
| i18n (0.7.0) | i18n (0.7.0) | ||||
| @@ -147,6 +149,7 @@ GEM | |||||
| thor (0.19.1) | thor (0.19.1) | ||||
| thread_safe (0.3.5) | thread_safe (0.3.5) | ||||
| tilt (2.0.5) | tilt (2.0.5) | ||||
| trollop (2.1.2) | |||||
| turbolinks (5.0.1) | turbolinks (5.0.1) | ||||
| turbolinks-source (~> 5) | turbolinks-source (~> 5) | ||||
| turbolinks-source (5.0.0) | turbolinks-source (5.0.0) | ||||
| @@ -171,6 +174,7 @@ DEPENDENCIES | |||||
| byebug | byebug | ||||
| coffee-rails (~> 4.2) | coffee-rails (~> 4.2) | ||||
| docsplit (~> 0.7.6) | docsplit (~> 0.7.6) | ||||
| filewatcher (~> 0.5.3) | |||||
| jbuilder (~> 2.5) | jbuilder (~> 2.5) | ||||
| jquery-rails | jquery-rails | ||||
| listen (~> 3.0.5) | listen (~> 3.0.5) | ||||
| @@ -8,9 +8,10 @@ Things you may want to cover: | |||||
| * Ruby version | * Ruby version | ||||
| Ruby 2.3.1 | Ruby 2.3.1 | ||||
| ``` | |||||
| ```ruby | |||||
| gem 'paperclip', '~> 5.0.0' | gem 'paperclip', '~> 5.0.0' | ||||
| gem 'docsplit', '~> 0.7.6' | gem 'docsplit', '~> 0.7.6' | ||||
| gem 'filewatcher', '~> 0.5.3' | |||||
| ``` | ``` | ||||
| * System dependencies | * System dependencies | ||||
| @@ -4,7 +4,11 @@ class DocumentsController < ApplicationController | |||||
| # GET /documents | # GET /documents | ||||
| # GET /documents.json | # GET /documents.json | ||||
| def index | def index | ||||
| @documents = User.find(session[:user_id]).documents | |||||
| if params[:search] | |||||
| @documents = User.find(session[:user_id]).documents.contains_word(params[:search]) | |||||
| else | |||||
| @documents = User.find(session[:user_id]).documents | |||||
| end | |||||
| end | end | ||||
| # GET /documents/1 | # GET /documents/1 | ||||
| @@ -67,6 +71,12 @@ class DocumentsController < ApplicationController | |||||
| end | end | ||||
| end | end | ||||
| # GET /documents/search | |||||
| def search | |||||
| end | |||||
| # GET | |||||
| private | private | ||||
| # Use callbacks to share common setup or constraints between actions. | # Use callbacks to share common setup or constraints between actions. | ||||
| def set_document | def set_document | ||||
| @@ -0,0 +1,27 @@ | |||||
| class ContentGenerationJob < ApplicationJob | |||||
| require 'docsplit' | |||||
| @document_id = nil | |||||
| queue_as :default | |||||
| after_perform :generate_tags | |||||
| def perform(document_id) | |||||
| @document_id = document_id | |||||
| document = Document.find(document_id) | |||||
| Docsplit.extract_text(document.doc.path, output: 'tmp/raw_content') | |||||
| file_path = 'tmp/raw_content/' + File.basename(document.doc.path, 'pdf') + 'txt' | |||||
| text = IO.read(file_path) | |||||
| content = document.build_content(text: text) | |||||
| content.save! | |||||
| File.delete(file_path) if File.exist?(file_path) | |||||
| end | |||||
| private | |||||
| def generate_tags | |||||
| TagGenerationJob.perform_now @document_id | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,16 @@ | |||||
| class TagGenerationJob < ApplicationJob | |||||
| queue_as :default | |||||
| def perform(document_id) | |||||
| document = Document.find(document_id) | |||||
| content = document.content | |||||
| words = content.text.squish.split(/\s+/) | |||||
| h = Hash.new(0) | |||||
| content.text.squish.split(/\s+/).delete_if{ |w| w.length <= 3 }.each { |w| h[w] += 1 } | |||||
| h.sort_by { |key, value| value } | |||||
| # stop list... | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,3 @@ | |||||
| class Content < ApplicationRecord | |||||
| belongs_to :document | |||||
| end | |||||
| @@ -1,6 +1,7 @@ | |||||
| class Document < ApplicationRecord | class Document < ApplicationRecord | ||||
| belongs_to :user | belongs_to :user | ||||
| belongs_to :category | belongs_to :category | ||||
| has_one :content, dependent: :destroy, required: false | |||||
| has_and_belongs_to_many :tags | has_and_belongs_to_many :tags | ||||
| has_attached_file :doc, | has_attached_file :doc, | ||||
| @@ -10,4 +11,16 @@ class Document < ApplicationRecord | |||||
| hash_secret: Rails.application.secrets.secret_key_base | hash_secret: Rails.application.secrets.secret_key_base | ||||
| } | } | ||||
| validates_attachment_content_type :doc, content_type: 'application/pdf' | validates_attachment_content_type :doc, content_type: 'application/pdf' | ||||
| after_save :generate_content | |||||
| scope :contains_word, -> (word) { joins(:content).where("text like ?", "%#{word}%") } | |||||
| private | |||||
| def generate_content | |||||
| if self.doc_content_type == 'application/pdf' | |||||
| ContentGenerationJob.perform_now self.id | |||||
| end | |||||
| end | |||||
| end | end | ||||
| @@ -1,4 +1,4 @@ | |||||
| <%= form_for document, url: documents_path, html: { multipart: true } do |f| %> | |||||
| <%= form_for document, html: { multipart: true } do |f| %> | |||||
| <% if document.errors.any? %> | <% if document.errors.any? %> | ||||
| <div id="error_explanation"> | <div id="error_explanation"> | ||||
| <h2><%= pluralize(document.errors.count, "error") %> prohibited this document from being saved:</h2> | <h2><%= pluralize(document.errors.count, "error") %> prohibited this document from being saved:</h2> | ||||
| @@ -0,0 +1,11 @@ | |||||
| <p id="notice"><%= notice %></p> | |||||
| <h1>Search documents</h1> | |||||
| <%= form_tag documents_path, :method => 'get' do %> | |||||
| <p> | |||||
| <%= label_tag 'Search string' %> | |||||
| <%= text_field_tag :search, params[:search] %> | |||||
| <%= submit_tag 'Search' %> | |||||
| </p> | |||||
| <% end %> | |||||
| @@ -14,5 +14,17 @@ | |||||
| <%= link_to @document.doc_file_name, @document.doc.url %> | <%= link_to @document.doc_file_name, @document.doc.url %> | ||||
| </p> | </p> | ||||
| <% if @document.content %> | |||||
| <p> | |||||
| <strong>Content:</strong> | |||||
| <%= @document.content.text.truncate_words(30) %> | |||||
| </p> | |||||
| <p> | |||||
| <strong>Words (length > 3):</strong> | |||||
| <%= @document.content.text.squish.split(/\s+/).uniq.delete_if { |w| w.length <= 3 } %> | |||||
| </p> | |||||
| <% end %> | |||||
| <%= link_to 'Edit', edit_document_path(@document) %> | | <%= link_to 'Edit', edit_document_path(@document) %> | | ||||
| <%= link_to 'Back', documents_path %> | <%= link_to 'Back', documents_path %> | ||||
| @@ -27,7 +27,10 @@ | |||||
| </ul> | </ul> | ||||
| <ul> | <ul> | ||||
| <li> | <li> | ||||
| <a href="documents/new">New</a> | |||||
| <%= link_to 'New', new_document_path %> | |||||
| </li> | |||||
| <li> | |||||
| <%= link_to 'Search', search_documents_path %> | |||||
| </li> | </li> | ||||
| </ul> | </ul> | ||||
| <%= button_to 'Logout', logout_path, method: :delete %> | <%= button_to 'Logout', logout_path, method: :delete %> | ||||
| @@ -2,7 +2,14 @@ Rails.application.routes.draw do | |||||
| root 'documents#index', as: 'documents_index' | root 'documents#index', as: 'documents_index' | ||||
| resources :categories | resources :categories | ||||
| resources :documents | |||||
| resources :documents do | |||||
| get :search, on: :collection | |||||
| # collection do | |||||
| # get 'search' | |||||
| # end | |||||
| end | |||||
| resources :users | resources :users | ||||
| controller :sessions do | controller :sessions do | ||||
| @@ -0,0 +1,10 @@ | |||||
| class CreateContents < ActiveRecord::Migration[5.0] | |||||
| def change | |||||
| create_table :contents do |t| | |||||
| t.text :content | |||||
| t.references :document | |||||
| t.timestamps | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,5 @@ | |||||
| class RenameContentColumnToText < ActiveRecord::Migration[5.0] | |||||
| def change | |||||
| rename_column :contents, :content, :text | |||||
| end | |||||
| end | |||||
| @@ -10,7 +10,7 @@ | |||||
| # | # | ||||
| # It's strongly recommended that you check this file into your version control system. | # It's strongly recommended that you check this file into your version control system. | ||||
| ActiveRecord::Schema.define(version: 20161124223446) do | |||||
| ActiveRecord::Schema.define(version: 20161125201757) do | |||||
| create_table "categories", force: :cascade do |t| | create_table "categories", force: :cascade do |t| | ||||
| t.string "name" | t.string "name" | ||||
| @@ -22,6 +22,14 @@ ActiveRecord::Schema.define(version: 20161124223446) do | |||||
| t.index ["user_id"], name: "index_categories_on_user_id" | t.index ["user_id"], name: "index_categories_on_user_id" | ||||
| end | end | ||||
| create_table "contents", force: :cascade do |t| | |||||
| t.text "text" | |||||
| t.integer "document_id" | |||||
| t.datetime "created_at", null: false | |||||
| t.datetime "updated_at", null: false | |||||
| t.index ["document_id"], name: "index_contents_on_document_id" | |||||
| end | |||||
| create_table "documents", force: :cascade do |t| | create_table "documents", force: :cascade do |t| | ||||
| t.string "name" | t.string "name" | ||||
| t.datetime "created_at", null: false | t.datetime "created_at", null: false | ||||
| @@ -0,0 +1,9 @@ | |||||
| # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html | |||||
| one: | |||||
| content: MyText | |||||
| document: | |||||
| two: | |||||
| content: MyText | |||||
| document: | |||||
| @@ -0,0 +1,7 @@ | |||||
| require 'test_helper' | |||||
| class ContentGenerationJobTest < ActiveJob::TestCase | |||||
| # test "the truth" do | |||||
| # assert true | |||||
| # end | |||||
| end | |||||
| @@ -0,0 +1,7 @@ | |||||
| require 'test_helper' | |||||
| class TagGenerationJobTest < ActiveJob::TestCase | |||||
| # test "the truth" do | |||||
| # assert true | |||||
| # end | |||||
| end | |||||
| @@ -0,0 +1,7 @@ | |||||
| require 'test_helper' | |||||
| class ContentTest < ActiveSupport::TestCase | |||||
| # test "the truth" do | |||||
| # assert true | |||||
| # end | |||||
| end | |||||