views:

825

answers:

2

The models project and category are in a has_and_belongs_to_many relationship. The partial seen below is used on different views to show a dropdown-menu with all the available categories. The projects in the list below the dropdown-menu are shown according to the choice the user made in the dropdown-menu.

Besides other categories, there is a category named "Everything" that every project is member of. It's also the first entry in the category-db-table, because it got inserted in while loading the migrations into the database.

Right now there is no error, but regardless of which category I choose it reloads the page showing the "Everything" category.

Any idea what I need to change in the code mentioned below to make it work the way I want to? Thanks for your help!

Partial with dropdown-menu and project-list

<!-- category dropdown -->
<% form_for category_url(:id), :html => {:method => :get} do |f| %>
    <label>Categories</label>
     <%= f.collection_select(:category_ids , Category.find(:all), :id , :name) %>
     <%= f.submit "Show" %>
<% end %>

<!-- project list -->
<ul class="projectlist">
  <% @projects.each do |_project| %>
    <li>
      <%= link_to(_project.name, _project) %>
    </li>
  <% end %>
</ul>

Logoutput after choosing category with id 2 on the dropdown-menu

Processing ProjectsController#index (for 127.0.0.1 at 2009-02-20 17:26:10) [GET]
  Parameters: {"commit"=>"Show", "http://localhost:3000/categories/id"=&gt;{"category_ids"=&gt;"2"}}

Category Model

class Category < ActiveRecord::Base
  has_and_belongs_to_many :projects, :join_table => "categories_projects"
end

Categories Controller

class CategoriesController < ApplicationController
  def show
    @projects = Category.find(params[:id]).projects.find(:all)

    respond_to do |format|
      format.html # show.html.erb
    end
  end
end

Project Model

class Project < ActiveRecord::Base
  has_and_belongs_to_many :categories, :join_table => "categories_projects"
end

Projects Controller

class ProjectsController < ApplicationController
  def show
    @projects = Project.find(:all)
    @project = Project.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
    end
  end

  def index
    @projects = Project.find(:all)

    respond_to do |format|
      format.html # index.html.erb
    end
  end
end

part of 'rake routes' output

category GET    /categories/:id  {:controller=>"categories", :action=>"show"}
A: 

You're passing a parameter called :category_ids, but you're not accessing that anywhere.

form_for category_url(:id)

This will submit your form to the path /categories/1 or whatever id you're currently viewing. You're then using that :id for finding your category projects:

@projects = Category.find(params[:id]).projects.find(:all)

So you're just showing the same ones over again. Because it's a form, you're submitting a query with the :category_ids parameter:

POST /categories/1?category_ids=2

You could just change your Category.find to use the other parameter instead. But, normally to view category 2 you would just use the url /categories/2, where 2 is your :id parameter. You have two ids in that path, and you should decide how you want to resolve that.

One option is to use the categories_path for the form action, and change the collection_select :category_ids parameter to just :id:

/categories?id=2  # from the form
/categories/2     # from a link

But if you're just listing projects, I would move this logic into the projects controller (index action), so your URLs would look like:

/projects?category_id=2` # from the form
/categories/2/projects   # from a link
Andrew Vit
A: 

Thanks Andrew, but I solved it myself this way:

I got rid of *collection_select*, changed to select, added the filter-action (with the according route in config/routes.rb) and now everything works as I expected.

...I'm trying to get an observer on the select-menu, that submits it's value to the filter-action as soon as the user changes the selection in the select-menu, but that's another story. ;-)

New partial with dropdown-menu and project-list

    <% form_tag(filter_category_path(:id), :method => :post, :class => 'categories') do %>
       <label>Categories</label>
       <%= select_tag(:category, options_for_select(Category.all.map {|category| [category.name, category.id]}, @category.id)) %>
       <%= submit_tag "Go" %>
     <% end %>

   <ul class="projects">
     <% @projects.each do |_project| %>
       <li>
         <%= link_to(_project.name, _project) %>
       </li>
     <% end %>
   </ul>

New categories controller

class CategoriesController < ApplicationController
  def show
    @category = Category.find(params[:id])
    @projects = @category.projects.find(:all)

    respond_to do |format|
      format.html 
    end
  end

  def filter
    @category = Category.find(params[:category])
    @projects = @category.projects.find(:all)

    respond_to do |format|
      format.html
    end    
  end
end
Javier