mercredi 21 mars 2018

typeahead rails 3 autocomplete with user per request

The app is using typeahead and bootstrap 3 for, autocomplete function. but now we have so many records that , it is getting really slower.

   var substringMatcher = function(strs) {
        return function findMatches(q, cb) {
            var matches, substrRegex;

            // an array that will be populated with substring matches
            matches = [];

            // regex used to determine if a string contains the substring `q`
            substrRegex = new RegExp(q, 'i');

            // iterate through the pool of strings and for any string that
            // contains the substring `q`, add it to the `matches` array
            $.each(strs, function(i, str) {
                if (substrRegex.test(str)) {
                    // the typeahead jQuery plugin expects suggestions to a
                    // JavaScript object, refer to typeahead docs for more info
                    matches.push({ value: str });
                }
            });

            cb(matches);
        };
    };


$('.typeahead').each(function(elem) {
        $(elem).typeahead({
            hint: false,
            highlight: true,
            minLength: 3
        }, {
            displayKey: 'value',
            source: substringMatcher($(elem).data('source'))
        });
    });

these are javasxript parts of typeahead fuction used by the app

on the view side of the form

<div class="form-group">
        <label class="col-sm-2 control-label" for="typeahead_book">Title</label>
        <div class="col-sm-3">
        <input value="<%=@option.book.try(:title)%>" name="option[book_title]" type="text" class="form-control typeahead typeahead-remote-book" id="typeahead_book"  data-provide="typeahead" data-items="10" data-source='<%=@book_titles%>'>
          <p class="help-block"><small><%= $autocomplete_message %></small></p>
        </div>

i use a callback as

before_filter :get_autocomplete_lists, only: [:new, :edit]

def get_autocomplete_lists

    @book_titles = Rails.cache.fetch("booktitles", :force => true, expires_in: 10.minutes) do 
      Book.scoped.map(&:title)
    end


    @publisher_names = Rails.cache.fetch("publishernames", :force => true, expires_in: 10.minutes) do 
      Publisher.all.map(&:name)
    end


    @users_by_email_name = Rails.cache.fetch("users",  :force => true, expires_in: 7.days) do 
      User.scoped.map{|user| "#{user.email} - #{user.name}"}
    end 


    @country_names = Rails.cache.fetch("countrynames",  :force => true, expires_in: 7.days) do
      Country.all.map(&:first).sort
    end
    # @languages = LanguageList::COMMON_LANGUAGES.map(&:name)
    # @country_names = Anatolialit::Country::List.sort
    # 

    @languages = Rails.cache.fetch("languages",  :force => true, expires_in: 7.days) do 
      Anatolialit::Language::EnList.sort
    end

  end

on controller that generates source of the book , as @book_titles , THE APP IS WORKING NOW but i have to refactor the code for performance issues.Because after 10k record @book_titles is very big.


THAN WHAT I DID i created a new controller action on application controller
def book_titles
     searchterm = (params[:title])
     books =Book.any_of({ :title => /.*#{searchterm}.*/ })
     respond_to do |format|
      format.json { render json: books.map(&:title)  }
     end
  end


and i defined a route to use as application controller as an api service

get 'booktitles/:title' => 'application#book_titles', format: :json

now when i use a localhost:3000/booktitles/the it brings me as a json data all the books that indicates 'the' in the title. I think everything Until here is ok. about refactoring.


but when i use this code below for userside per request for sourcing typeahead
$(document).ready(function() {
  $('.typeahead-remote-book').typeahead({
      source: function (query, process) {
          return $.get('/booktitles', { query: query }, function (data) {
              return typeahead.process(data);
          });
      }
  });
});


and i changed the view part of the form to

<div class="form-group">
        <label class="col-sm-2 control-label" for="typeahead_book">Title</label>
        <div class="col-sm-3">
        <input value="<%=@option.book.try(:title)%>" name="option[book_title]" type="text" class="form-control typeahead typeahead-remote-book" id="typeahead_book"  data-provide="typeahead" data-items="10" >
          <p class="help-block"><small><%= $autocomplete_message %></small></p>
        </div>
      </div>

*I do not know what is wrong with the situation , but it does not work *

could u please help me ? about solving the problem. Thanks for your kind help.. best regards.

Aucun commentaire:

Enregistrer un commentaire