Forum: Ruby on Rails Association Methods

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Jette C. (Guest)
on 2008-10-13 11:35
(Received via mailing list)
I am a newbie of ruby on rails. And I have met a problem with model
association.

I have 2 tables here, one is "item" the other is "brand", when I
create one new item, I want to select one brand from the list.

Here are the models:

class Brand < ActiveRecord::Base
  has_many :items
end

class Item < ActiveRecord::Base
  belongs_to :brand
end

for item/new view
<% form_for(@item) do |f| %>
  <%= f.error_messages %>

  <p>
    <%= f.label :Brand %><br />
    <%= f.collection_select(:brand, Brand.find(:all), :id, :name,
{:prompt => "please select one brand"}) %>
  </p>
...


I can get the list successfully when create the new item, but when I
press the "create" button, I've got the "Brand(#57323960) expected,
got String(#21132310)" AssociationTypeMismatch error

I am not sure why I got the AssociationTypeMismatch error, and how can
I handle this?
Daniel B. (Guest)
on 2008-10-13 12:20
(Received via mailing list)
On Oct 13, 4:38 pm, Daniel <removed_email_address@domain.invalid> wrote:
> end
>     <%= f.label :Brand %><br />
>     <%= f.collection_select(:brand, Brand.find(:all), :id, :name,
> {:prompt => "please select one brand"}) %>

I sometimes find these helper methods quite confusing.  The key is
what parameters they are sending back to your controller when you hit
the create button.
Check your logs if you're unsure.
The above line is probably sending
  params[:item][:brand] => <brand-id>
where <brand-id> is the id number for an existing brand.
Another way to check is to look at the generated select tag; it will
probably be <select name="item[brand]" ...>  (note how 'params' builds
its hash structure off the 'name' attribute).

You might want to change it to:
     <%= f.collection_select(:brand_id, Brand.find(:all), :id, :name,
 {:prompt => "please select one brand"}) %>

It depends on what your 'create' controller is doing; I assume you're
just instantiating a new item object and passing over the field values
from 'params'.  So if your object sees params[:item][:brand_id] you
might get what you want - the <brand-id> will be inserted into the
items.brand_id field.  If it sees 'brand' as per the original, then
I'm guessing it's trying to build the assocation via the Item#brand
association method which probably expects a Brand object and not its
id (in string form).

I always have to go back and check the docs.  So what I've said above
might not be totally right.  Get to know how 'params' is generated.
Writing stuff test-first on your functional tests will start you
thinking like this too.

Daniel
Jette C. (Guest)
on 2008-10-13 12:32
(Received via mailing list)
Well, thank you very much Daniel :-) your information is quite useful

I checked my code, yes, it is like <select name="item[brand]" ...>
I forgot to mentioned that, I have tried to use "<%=
f.collection_select(:brand_id, Brand.find(:all), :id, :name,
 {:prompt => "please select one brand"}) %> "
But, I have got another error "undefined method `brand_id' for #<Item:
0x6ce3258>"
I assumed maybe there is another place I should take care of? in the
items controller?

I was totally confused, sorry.
Daniel B. (Guest)
on 2008-10-13 12:45
(Received via mailing list)
On Oct 13, 7:32 pm, Daniel <removed_email_address@domain.invalid> wrote:
> Well, thank you very much Daniel :-) your information is quite useful
>
> I checked my code, yes, it is like <select name="item[brand]" ...>
> I forgot to mentioned that, I have tried to use "<%=
> f.collection_select(:brand_id, Brand.find(:all), :id, :name,
>  {:prompt => "please select one brand"}) %> "
> But, I have got another error "undefined method `brand_id' for #<Item:
> 0x6ce3258>"

Just to make sure: do you have a brand_id integer field in your items
table?
What is the code for your controller - the thing you're posting to?

Daniel
Paul Y. (Guest)
on 2008-10-13 21:54
Hi I have been following this discussion and I have added a
brand_id:integer field to my items table. The create button now works
and populates the brand column with a number.

I've added this to the item show view:

<% for brand in Brand.find(:all, :conditions => {:id => @item.id}) %>
  <div>
    <%= brand.name %>
  </div>
<% end %>

However some of the brand names are not the name I selected when I
created the entry.
Frederick C. (Guest)
on 2008-10-13 21:59
(Received via mailing list)
On Oct 13, 6:54 pm, Paul Y. <removed_email_address@domain.invalid>
wrote:
> <% end %>
>
> However some of the brand names are not the name I selected when I
> created the entry.

is this suppose to show the brands for a particular item? The above
can't do that - you're selecting brands whose id matches the items id,
the results will be unpredictable at best. @item.brand contains the
brand you selected for the item.

Fred
Paul Y. (Guest)
on 2008-10-13 22:05
I changed it to this, which appears to work correctly:

<% for brand in Brand.find(:all, :conditions => {:id => @item.brand_id})
%>
  <div>
    <%= brand.name %>
  </div>
<% end %>
Paul Y. (Guest)
on 2008-10-13 22:17
So now in my brands view I'm trying to show all of the items associated
with that brand.

The following returns all items:

<% for item in Item.find(:all) %>
  <%= item.name %>
<% end %>


But obviously I only want the items for a particular brand, so I tried:

<% for item in Item.find(:all, :conditions => {:brand_id => @brand.id})
%>
  <%= item.name %>
<% end %>

But I get an error
Paul Y. (Guest)
on 2008-10-13 22:20
Removed the @ sign from :brand_id => @brand.id:

<% for item in Item.find(:all, :conditions => {:brand_id => brand.id})
%>
  <%= item.name %>
<% end %>

Which appears to have fixed things
Frederick C. (Guest)
on 2008-10-13 22:27
(Received via mailing list)
On Oct 13, 7:20 pm, Paul Y. <removed_email_address@domain.invalid>
wrote:
> Removed the @ sign from :brand_id => @brand.id:
>
> <% for item in Item.find(:all, :conditions => {:brand_id => brand.id})
> %>
>   <%= item.name %>
> <% end %>
>
> Which appears to have fixed things

While this works, things will be a lot more concise and less error
prone if you use the associations, for example the above simplifies to

<% for item in brand.items %>
   <%= item.name %>
<% end %>
Paul Y. (Guest)
on 2008-10-13 22:49
What if I only wanted to show the latest item added?
Paul Y. (Guest)
on 2008-10-13 23:00
I've tried:

<% for item in brand.items.find(:last) %>
  <%= item.name %>
<% end %>
Paul Y. (Guest)
on 2008-10-13 23:15
So I'm using:

<% for item in Item.find(:all, :conditions => {:brand_id => brand.id},
:limit => "1") %>
  <%= item.name %>
<% end %>
Frederick C. (Guest)
on 2008-10-13 23:23
(Received via mailing list)
On Oct 13, 8:15 pm, Paul Y. <removed_email_address@domain.invalid>
wrote:
> So I'm using:
>
find :last only exist in rails 2.1
> <% for item in Item.find(:all, :conditions => {:brand_id => brand.id},
> :limit => "1") %>

that doesn't return the last item, it shows the first one (however
without an order specified that is not always well defined).

brand.items.find :first is the same as the above, you can add an order
clause to get the last item.

Fred
Paul Y. (Guest)
on 2008-10-15 10:21
I'm pretty sure I have 2.1 but I can't get :first or last to work in the
format you gave. It must be my syntax. Will post it later unless you can
provide a valid example?
This topic is locked and can not be replied to.