has_many / belongs_to associations

I have two models, Review and Album.

Album has many reviews, and Review belongs to Album as seen below in
their respective model files.

class Review < ActiveRecord::Base
  belongs_to :album
end

class Album < ActiveRecord::Base
  has_many :reviews
end

I then added a form to submit reviews for an album:

<% form_for @review do |f| %>
  <textarea cols="40" id="review_productReview"
name="review[productReview]" rows="10"></textarea><br>

  <input type='hidden' id="review_product" name="review[product]"
value='<%= @album.title%>' >
  <input type='hidden' id="review_productCreator"
name="review[productCreator]" value='<%= @album.artist%>' >
  <input name="commit" type="submit" value="Submit Review" />
<% end %>

In my controller I have :

class ReviewsController < ApplicationController

  def create
    @review=Review.new(params[:review])
    @review.album=@album
    @review.save
    redirect_to '/inventory'
  end

end

i'm not sure that @review.album=@album is the correct syntax, but even
at the command line when I instantiate an object of type Review and do
Review.album.title="GoldDigger", it says that album is an undefined
method. The only thing I can think of is that I am missing something
when I set up the associations.

Jon wrote:

  def create
    @review=Review.new(params[:review])
    @review.album=@album

thats correct syntax (if @album is a object of Album model)

i'm not sure that @review.album=@album is the correct syntax, but even
at the command line when I instantiate an object of type Review and do
Review.album.title="GoldDigger", it says that album is an undefined

here 'Review' is not a model object ,thats a model class

and always you can't get any association with any model class (except if
you write your own code inside of that model class)

first
@review=Review.find(id)
unless @review.album
@review.album=Album.find(id)
end
@review.album.title="GoldDigger"

class ReviewsController < ApplicationController

def create
@review=Review.new(params[:review])
@review.album=@album
@review.save
redirect_to '/inventory'
end

The problem you have is that @album is nil, because you haven't set it
to anything. It may have been set when you rendered the form, but that
was a different instance of the controller (quite possibly in a
different process or even server). You need to have whatever parameter
in the form you need to be able to retrieve that album, (eg a
hidden_field)

Fred

I tried manually defining @album like so

 id=1
 @review=Review.new(params[:review])
 @review.album=Album.find(id)
 @review.save

Because of this, I don’t think it’s that @album was not defined. Also as I brought up before, and I think this is key in showing their is something fundamentally wrong in my set up, the association doesn’t even work at the command line.

Ex:
a=Album.find(1)
r=Review.new
r.album=a

This yields an error that says “NoMethodError: undefined method ‘album=’ for #<Review:…”

Any insight?

Well the full stacktrace is sometimes helpful. Just to be sure, your
reviews table does have an album_id column ?

Fred

how do you view the stacktrace? I thin this is the solution to my problem…only now migrations is acting funny with me…

I'm only guessing here, but I'm thinking maybe that your issue is
centred around the way rails automagically creates the setter and
getter methods for associations. From what I'm seeing, I'm guessing
that has_many creates attr_writer methods whereas belongs_to only
creates attr_reader methods. What this means is, album= will not be an
accessible method, so trying to set the album within a "child"
association isn't possible (nor should it be). What you need to do is
simply set the album_id. I've never tried to create associative data
the way you are, so I can't say for sure this is the issue, but I
think it's possible. You generally don't create relationships via
belongs_to.

Going the other way, you shouldn't have any problems though.

Ie.

@album = Album.new( your params )
@album.reviews = [ Review.new( review1params ),
Review.new( review2.params ) ]
@album.save

.etc.etc.

Hope that helps.

Kirk "Torm3nt" Bushell

Nah, you can set a parent from a child. Dig it:

  >> hh = Album.new(:title => "Houses of the Holy", :artist => "Led Zepplin")
  => #<Album id: nil, title: "Houses of the Holy", artist: "Led Zepplin", release_date: nil, created_at: nil, updated_at: nil>
  >> hhr = Review.new(:title => "Led Zep's new album rocks", :review_body => "Best. Album. Ever.")
  => #<Review id: nil, title: "Led Zep's new album rocks", review_body: "Best. Album. Ever.", album_id: nil, created_at: nil, updated_at: nil>
  >> hh.save
  => true
  >> hhr.save
  => true
  >> hhr.album = hh
  => #<Album id: 1, title: "Houses of the Holy", artist: "Led Zepplin", release_date: nil, created_at: "2008-10-13 07:13:04", updated_at: "2008-10-13 07:13:04">
  >> hhr.save
  => true
  >>

-Roy