0

I had a problem where I was getting duplicate results in a search, in my rails app that allow the user to search for projects in a database.

Here is the search function in the project model:

def self.search(search_industry, search_role, search_techs_ids)

    _projects = Project.scoped 

    if search_industry.present?
      _projects = _projects.where ['industry LIKE ?', like(search_industry)]
    end
    if search_role.present?
      _projects = _projects.where ['role LIKE ?', like(search_role)]
    end
    if search_techs_ids.present?
    _projects = _projects.includes(:technols).where("technols.id" => search_techs_ids)
    end
    _projects
    end

and here is part of my search page

<div class="tech">
<%= fields_for(@project_technol) do |ab| %>
 Technologies : 
 <%     tech_ids = params[:technols][:id].reject(&:blank?) unless params[:technols].nil? %>

<%if params[:technols].nil?%>

<%= collection_select(:technols, :id, @all_technols, :id, :tech, {}, {:multiple => true} ) %>

<% else %>

<%= collection_select(:technols, :id, @all_technols, :id, :tech, {}, {:multiple => true, :selected => tech_ids } ) %>
<% end %>

</div>

Here is my search action:

def search

    tech_ids = params[:technols][:id].reject(&:blank?) unless params[:technols].nil?

    @search =  params[:industry], params[:role], tech_ids

    @project_search = Project.search(*@search).order(sort_column + ' ' + sort_direction).paginated_for_index(per_page, page)

    @search_performed = !@search.reject! { |c| c.blank? }.empty? 

  @project = Project.new(params[:project])

    @all_technols = Technol.all

    @project_technol = @project.projecttechnols.build

respond_to do |format|
      format.html # search.html.erb
      format.json { render :json => @project }
    end

end

That problem is now sorted, but in fixing that, I noticed that when I search for a single technology, the correct projects show up in the table, but in the technology column it is meant to show all the technologies belonging to that project but it only shows the one I searched for:

<% @project_search.each do |t| %>
  <tr>
    <td><ul>
      <% t.technols.each do |technol| %>
        <li><%= technol.tech %><!/li>
      <% end %>
    </ul></td>

Any ideas? In my model I used to have this code which worked for displaying the table correctly, but showed duplicate results.

if search_techs_ids.present?
        _projects = _projects.joins(:technols).where("technols.id" => search_techs_ids)
        end

Any help at all will be appreciated. Thanks in advance

SOLUTION see answers below

@shioyama and @tommasop both helped fix the problem.

The solution was to change my search view where the column is made to

<td><ul>
  <% t.technols(force_reload=true).each do |technol| %>
    <li><%= technol.tech %></li>

  <% end %>

</ul></td>
Jazz
  • 1,090
  • 6
  • 23
  • 55

2 Answers2

2

Try with this syntax:

_projects.each { |p| p.technols(force_reload=true) }
_projects

reference here.

tommasop
  • 18,495
  • 2
  • 40
  • 51
  • Sorry, still no change. Should I post my logs or something to help? – Jazz Oct 10 '12 at 13:28
  • 2
    If my understanding of `force_reload` is correct, `p.technols(force_reload=true)` will *return* the reloaded association, not reload it in place, so this won't work. – Chris Salzberg Oct 10 '12 at 13:43
1

I encountered the same problem in a different guise: Matching nested model association attribute with includes

See also this discussion on the globalize3 github issue page, where the problem came up when trying to destroy a record after searching by dynamic finder (leaving unmatched associations behind in the DB).

The problem is that you're restricting the join to projects with given technology associations (those with ids in search_tech_ids), so those are the only rows that rails returns. Rails has no way of knowing there are others there.

Basically so far as I can tell, the easiest solution is just to reload the projects after completing the search. Add a line just above the last line of your search method, like so:

_projects.each { |p| p.technols.reload }
_projects

This will tell rails to reload the technologies associated with each project, including the technologies it did not match in the search. I believe that should work in your case.

UPDATE:

After many attempts (see comments) and a suggestion from @tommasop, the solution was to force-reload the technologies in the view with:

t.technols(force_reload=true).each

Still not clear why the reload approach above wasn't working. If anyone has any insights please let me know, I'd be curious to hear.

Community
  • 1
  • 1
Chris Salzberg
  • 27,099
  • 4
  • 75
  • 82
  • Hi there, thanks for helping. I added your code, and there was no change. hmm – Jazz Oct 10 '12 at 12:52
  • 1
    Honestly I'm a bit puzzled that this doesn't work. @tommasop's answer makes me think it may be a caching issue, see e.g. this: http://stackoverflow.com/questions/966012/cant-reload-activerecord-association-from-controller – Chris Salzberg Oct 10 '12 at 13:47
  • This is a wild guess, but can you try wrapping the reload in an `uncached` block, like this: `uncached { _projects.each { |p| p.technols.reload } }`? ref: http://railspikes.com/2008/8/18/disabling-activerecord-query-caching-when-needed – Chris Salzberg Oct 10 '12 at 13:52
  • I just tried your code `uncached { _projects.each { |p| p.technols.reload } }` and there is still no change. This is a weird one :/ – Jazz Oct 10 '12 at 13:55
  • 1
    If that doesn't work, try changing the view code `t.technols.each do |technol|` to `t.technols(force_reload=true).each do |technol|`. That should force the view to reload the technologies when iterating through them. – Chris Salzberg Oct 10 '12 at 13:55
  • And finally, if *that* doesn't work, I'd suggest going into a console and typing: `projects = Project.scoped.includes(:technols).where("technols.id" => ); projects.first.technols` where is an id of a technology, and see what it gives you. If you don't get all the technologies for the project, then try `projects.first.technols.reload; projects.first.technols` and see if they come up. – Chris Salzberg Oct 10 '12 at 14:00
  • This one worked!! `t.technols(force_reload=true).each do |technol|` Thanks very much – Jazz Oct 10 '12 at 14:01
  • Great, it was a group effort ;) I'm curious what was going wrong with the other solutions. Suppose it was a caching issue. – Chris Salzberg Oct 10 '12 at 14:01