Topic: many to many association not working, keeps throwing no method errors

Hi, this is my first post. I am a rails and programming newbie... but I'm been reading constantly trying to get over this very very steep double learning curve... Agile Development, Ruby for Rails, Up and Running, Rails Recipes....

I am trying to do something that should be very simple but no matter how I do it, rails refuses to accept the association.

I have a many to many association between articles and groups. Groups is just a word I'm using for the concept of "category".

class Article < ActiveRecord::Base
  has_and_belongs_to_many :groups

class Group < ActiveRecord::Base
  has_and_belongs_to_many :articles
  acts_as_tree

I want my navigation buttons essentially just to filter all articles by the 'group' param sent by the view, if there is a group, or else return all articles.

Here are 3 coding attempts I've tried in my articles_controller:

Code Attempt  #1
-----------------
  def list
    @group_id = params['group']
    if @group_id
      a = Group.find (:all, :conditions => id = @group_id)
      @articles = a.groups
    else
      @articles = Article.find (:all)
    end
  end


Code Attempt #2
---------------
def list
    group_id = params[:group]
    if group_id
    @articles = Article.groups.find_all_by_group_id(:group)
  else
  @articles = Article.find (:all)
end
end



Code Attempt #3
-------------------

def list
  if params[:group]
    @group=Group.find[:group]
  else
    @articles = @group.articles || throw rescue Article.find (:all)
end
end


The errors that follow are annoying because they are being thrown on things that I shouldn't have to define, right? because they exist and should be accessible as a part of the model?

undefined local variable or method `article' for #<ArticlesController:0x249bd34>

or... I get a NoMethodError --- undefined method `groups' for #<Array:0x24c1ebc> on the first bit of code that I have above (on line 5)

or... undefined method `find_all_by_group_id' for Article:Class when I use code attempt #2

or... Couldn't find Group without an ID, using code attempt #3

This is making me despair!!!

Please help.

This is the view that passes the parameter, by the way:

    <ul id="mainnavigation">
        <li><%= link_to 'Students', :action => 'list', :group => 1 %></li>
        <li><%= link_to 'Fellows/Scholars', :action => 'list', :group => 2 %></li>
        <li><%= link_to 'Faculty', :action => 'list', :group => 3 %></li>
        <li><%= link_to 'Staff', :action => 'list', :group => 4 %></li>
        <li><%= link_to 'Community', :action => 'list', :group => 5 %></li>
        <li><%= link_to 'Alumnae', :action => 'list', :group => 6 %></li>
    </ul>

I seem to be able to create articles and to populate the article_group table with selected groups in the edit arena.

I just can't make the thing show articles by group....

thanks,
Elena

Re: many to many association not working, keeps throwing no method errors

Let's take a look at each error with the code and see if I can help you understand it:


elena wrote:

Code Attempt  #1
-----------------

  def list
    @group_id = params['group']
    if @group_id
      a = Group.find (:all, :conditions => id = @group_id)
      @articles = a.groups
    else
      @articles = Article.find (:all)
    end
  end

I get a NoMethodError --- undefined method `groups' for #<Array:0x24c1ebc> on the first bit of code that I have above (on line 5)

When calling Group.find(:all) in the code above, it returns an Array. Think of this as a list of many Group models. The Array object doesn't know anything about its contents, it's just a container that can hold anything. This is why it complains when you call "groups" on it. What you really want here is to fetch one group which you almost do in the 3rd attempt.


elena wrote:

Code Attempt #2
---------------

def list
  group_id = params[:group]
  if group_id
    @articles = Article.groups.find_all_by_group_id(:group)
  else
      @articles = Article.find (:all)
    end
end

undefined method `find_all_by_group_id' for Article:Class when I use code attempt #2

You are really close on this one. Here you are calling Article.groups.find_all_by_group_id. If you remove the "groups" part of this you'll get it right. The only other change is to pass the "group_id" variable to this method, like this:

def list
  group_id = params[:group]
  if group_id
    @articles = Article.find_all_by_group_id(group_id)
  else
      @articles = Article.find(:all)
    end
end

elena wrote:

Code Attempt #3
-------------------

def list
  if params[:group]
    @group=Group.find[:group]
  else
    @articles = @group.articles || throw rescue Article.find (:all)
  end
end

Couldn't find Group without an ID, using code attempt #3

Very close here too. The call to params[:group] is what returns the id of the group. When calling Group.find() you just need to include the "params" part:

@group = Group.find(params[:group])

The other problem is how the "if" condition works. If a group is specified, the @articles line never ends up getting called. Instead you should set the @articles variable in both the "if" and "else" portions (two times) so that at least one will be called no matter the conditions:

def list
  if params[:group]
    @group = Group.find(params[:group])
    @articles = @group.articles
  else
    @articles = Article.find(:all)
  end
end

Hopefully that clears up some confusion. I can clarify any of this code if you need more explanation.

Rails has a steep learning curve, especially if this is your first programming language. You may want to take some time to learn Ruby on its own then come back to Rails.

Railscasts - Free Ruby on Rails Screencasts

Re: many to many association not working, keeps throwing no method errors

Thank you *so* much, I think I see what I was doing wrong, especially in the if clause...

You are very kind to answer me...

Elena