Search code examples
jqueryruby-on-railsruby-on-rails-4jquery-autocomplete

How to fill input text from another autocomplete Rails 4


I have a form with a task(uses Rails4 autocomplete gem) and a project text_field. I want to be able to fill it just from selecting a task.

So if I have

  • task1 : project1

When I type 'ta', and select task1 from the autocomplete, I want the project field to be filled with the correspondent project (project1 in this case).

This is the form:

<%= form_for :instance, url: instances_path do |f| %>
  <%= f.label :task_name %>
  <%= f.autocomplete_field :task_name,   autocomplete_task_name_static_pages_path %>
  <%= f.text_field :project_name %>
<% end %>

And this is the controller:

class StaticPagesController < ApplicationController
  autocomplete :task, :name
end

Reading the documentation I've tried adding :

:display_value => :task_full_info

and

class Task < ActiveRecord::Base 
  belongs_to :project

  def task_full_info
    self.project.name
  end
end

But that doesn't work. What's the proper way of doing it on Rails 4 with the rails4-autocomplete gem? Also, what changes should I make if I change the project text_field to a dropdownlist?

EDIT: Server log:

Started GET "/static_pages/autocomplete_task_name?term=do" for ... at 2016-05-05 18:05:50 -0300
Processing by StaticPagesController#autocomplete_task_name as JSON
  Parameters: {"term"=>"do"}
  User Load (1.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ?  ORDER BY "users"."id" ASC LIMIT 1  [["id", 1]]
  Task Load (0.4ms)  SELECT  "tasks"."id" as id, "tasks"."name" as name, "project_name", "tasks"."project_id" FROM "tasks" WHERE (LOWER(name) LIKE 'do%')  ORDER BY LOWER(name) ASC LIMIT 10
  Project Load (0.3ms)  SELECT  "projects".* FROM "projects" WHERE "projects"."id" = ? LIMIT 1  [["id", 7]]
Completed 200 OK in 10ms (Views: 0.3ms | ActiveRecord: 1.9ms)

Solution

  • From the documentation you linked, I see here what you want to do with :project_name. So your code would look something like:

    <%= form_for :instance, url: instances_path do |f| %>
      <%= f.label :task_name %>
      <%= f.autocomplete_field :task_name, autocomplete_task_name_static_pages_path, :update_elements => {:project_name => '#instance_project_name'} %>
      <%= f.text_field :project_name %>
    <% end %>
    

    I'm assuming here that instance_project_name is the actual id of the :project_name text field (it should if the code is as you stated).

    class StaticPagesController < ApplicationController
      autocomplete :task, :name, :extra_data => [:project_id, :project_name]
    end
    
    class Task < ActiveRecord::Base 
      belongs_to :project
    
      delegate :name, to: :project, prefix: true
    end
    

    I'd also recommend you to change your gem to this one, since it's linked from the documentation and seems to be more updated than the one you are using.

    Update:

    As it turns out, the gem does the following when autocomplete triggers:

    1) Makes an Activerecord select given the autocomplete field and what's given on the extra_data option. So that's why the weird "project_name" in the Task query from your log.

    2) Then it takes that Activerecord result and uses the send method for each requested field (again, the autocomplete field and the ones specified on extra_data).

    That's why whenever you need a field from a joined table, as a workaround, it's required that you put on extra data the foreing_key, since otherwise 1) won't have access to that foreign key and when 2) it's executed it won't find the association.

    I guess the gem could be improved by always selecting all foreign keys in 1) query but for now you'll have to settle with the workaround.