Polymorphic Problem

Hi. I believe that I need to write a method to get my user's
information, but I'm not sure how to write this and where it should go.

I have Reviews as polymorphic and there are several types items that can
be reviewed (books, music, movies, etc). A user can search for a book
and see all of the reviews for that book. Posted with each review, I
want to provide the name of the user. Based on what I have, what is the
best way to do this and where does this code go? Right now if I pull up
the book, I can see all of the reviews. In the review table I have the
review_user_id and now I want to display the name of that user from the
users table.

Here's my basic structure, but noting that I have put snippets of the
data here for brevity.

class CreateReviews < ActiveRecord::Migration
  def self.up
    create_table :reviews
      t.string :reviewable_type
      t.integer :reviewable_id
      t.string :title
      t.text :body
      t.integer :review_user_id
    end
  end
end

class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users
      t.string :name
    end
  end
end

class Review < ActiveRecord::Base
  belongs_to :reviewable, :polymorphic => true
end

class Book < ActiveRecord::Base
  has_many :reviews, :as => reviewable
end

class User < ActiveRecord::Base
  has_many :reviews, :as => :reviewable
end

THANKS!

Please see the above post for the setup of my models.

While trying to figure this out, I put this into script/console:

Book.find(1).reviews

=> [<#Review id: 2, reviewable_type: "Book", reviewable_id: 1,
review_user_id: 1>]

How can I take the value of review_user_id and get the name of the user
in the users table?

Thanks!

If your review model looks like this:

class Review
  belongs_to :user
  belongs_to :reviewable, :polymorphic => true
end

You could probably do something like this:

Book.find(1).reviews.each do |r|
  puts r.user.name
end

You need to let ActiveRecord know about the association:
(You don't specify the Rails version you're using, but I'm guessing 2.x)

class Review < ActiveRecord::Base
  belongs_to :reviewable, :polymorphic => true
  belongs_to :review_user, :class_name => 'User'
  # or perhaps:
  # belongs_to :reviewer, :class_name => 'User', :foreign_key => 'review_user_id'
end

class Book < ActiveRecord::Base
  has_many :reviews, :as => reviewable
end

class User < ActiveRecord::Base
  has_many :reviews, :as => :reviewable # can users be reviewed like Books, etc.?

  # if you mean for user.reviews to be the set of reviews
  # that this user wrote, then you want:
  has_many :reviews, :foreign_key => 'review_user_id'
end

Does that work for you?

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

You need to let ActiveRecord know about the association:
(You don't specify the Rails version you're using, but I'm guessing 2.x)

Yes, using Rails 2.1

class User < ActiveRecord::Base
  has_many :reviews, :as => :reviewable # can users be reviewed like
Books, etc.?

  # if you mean for user.reviews to be the set of reviews
  # that this user wrote, then you want:
  has_many :reviews, :foreign_key => 'review_user_id'
end

In my reviews table I have 2 user values, created_by and modifed_by.
Users can not be reviewed, but you can view all of the reviews per user.
Can I do the foreign key like you have in your second example if my
review table has 2 fields that link back to the user.id field?

Then you need to give the proper foreign_key

class User
   has_many :reviews, :foreign_key => 'created_by'
end

class Review
   belongs_to :creator, :class_name => 'User', :foreign_key => 'created_by'
end

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

Rob Biedenharn wrote:

Then you need to give the proper foreign_key

class User
   has_many :reviews, :foreign_key => 'created_by'
end

class Review
   belongs_to :creator, :class_name => 'User', :foreign_key =>
'created_by'
end

I must be missing what you're telling me because I get an error.
Polymorphic associations are new to me and quite confusing. I've read a
lot, but still don't quite understand how to set these up.

C:/project/vendor/rails/activesupport/lib/active_support/dependencies.rb:2
15:in `load_without_new_constant_marking':
C:/var/intranet3/app/models/user.rb:1
55: parse error, unexpected kEND, expecting $ (SyntaxError)

class CreateReviews < ActiveRecord::Migration
  def self.up
    create_table :reviews
      t.string :reviewable_type
      t.integer :reviewable_id
      t.string :title
      t.text :body
      t.integer :create_review_user_id
      t.integer :modify_review_user_id
    end
  end
end

class User
    has_many :reviews, :foreign_key => 'create_review_user_id'
has_many :reviews, :foreign_key => 'modify_review_user_id'
end

class Review
    belongs_to :creator, :class_name => 'User', :foreign_key =>
'create_review_user_id'
belongs_to :modified, :class_name => 'User', :foreign_key =>
'modify_review_user_id'
end

Rob Biedenharn wrote:

Then you need to give the proper foreign_key

class User
  has_many :reviews, :foreign_key => 'created_by'
end

class Review
  belongs_to :creator, :class_name => 'User', :foreign_key =>
'created_by'
end

I must be missing what you're telling me because I get an error.
Polymorphic associations are new to me and quite confusing. I've read a
lot, but still don't quite understand how to set these up.

C:/project/vendor/rails/activesupport/lib/active_support/dependencies.rb:2
15:in `load_without_new_constant_marking':
C:/var/intranet3/app/models/user.rb:1
55: parse error, unexpected kEND, expecting $ (SyntaxError)

class CreateReviews < ActiveRecord::Migration
def self.up
   create_table :reviews

missing: do |t|

     t.string :reviewable_type
     t.integer :reviewable_id
     t.string :title
     t.text :body
     t.integer :create_review_user_id
     t.integer :modify_review_user_id
   end
end
end

class User
   has_many :reviews, :foreign_key => 'create_review_user_id'
has_many :reviews, :foreign_key => 'modify_review_user_id'

You can't call both associations "reviews"
has_many :created_reviews, ...
has_many :editted_reviews, ...

end

class Review
   belongs_to :creator, :class_name => 'User', :foreign_key =>
'create_review_user_id'
belongs_to :modified, :class_name => 'User', :foreign_key =>
'modify_review_user_id'

belongs_to :modifier might be a better name than 'modifiED'

end

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

Ok, here's what I have in my models.

class Review < ActiveRecord::Base
  belongs_to :reviewable, :polymorphic => true
  belongs_to :created_reviews, :class_name => 'User', :foreign_key =>
'create_review_user_id'
  belongs_to :modified_reviews, :class_name => 'User', :foreign_key =>
'modify_review_user_id'
end

class User < ActiveRecord::Base
  has_many :reviews, :as => :reviewable
  has_many :created_reviews, :foreign_key => 'create_review_user_id'
  has_many :modified_reviews, :foreign_key => 'create_review_user_id'

Sorry I'm so dense, but after all of that, how do I access User.name?

review.created_reviews.name

Maurício Linhares wrote:

review.created_reviews.name

I wasn't sure where this should all go, but I am still getting errors.
Here's what I did in script/console:

Book.find(1).reviews

=> [<#Review id: 2, reviewable_type: "Book", reviewable_id: 1,
create_review_user_id: 1>]

review.created_reviews.name

=> NameError: undefined local variable or method `review' for
#<Object:0x18fa38>
        from (irb):9

If I put this in, I also get an error.

Book.find(1).reviews.each do |r|

?> puts review.created_reviews.name

end

NameError: undefined local variable or method `review' for
#<Object:0x18fa38>
        from (irb):11

Clearly I'm lost and confused. Thanks for helping out this new ruby
girl.

Ok, here's what I have in my models.

class Review < ActiveRecord::Base
belongs_to :reviewable, :polymorphic => true
belongs_to :created_reviews, :class_name => 'User', :foreign_key =>
'create_review_user_id'

This would be clearer as something singular (like 'reviewer') since a belongs_to is going to give a single associated record.

belongs_to :modified_reviews, :class_name => 'User', :foreign_key =>
'modify_review_user_id'
end

class User < ActiveRecord::Base
has_many :reviews, :as => :reviewable
has_many :created_reviews, :foreign_key => 'create_review_user_id'
has_many :modified_reviews, :foreign_key => 'create_review_user_id'

Perhaps you meant for the second one to be 'modify_review_user_id'?

Sorry I'm so dense, but after all of that, how do I access User.name?

Maurício Linhares wrote:

review.created_reviews.name

I wasn't sure where this should all go, but I am still getting errors.
Here's what I did in script/console:

Book.find(1).reviews

=> [<#Review id: 2, reviewable_type: "Book", reviewable_id: 1,
create_review_user_id: 1>]

review.created_reviews.name

=> NameError: undefined local variable or method `review' for
#<Object:0x18fa38>
       from (irb):9

review = Book.find(1).reviews.first

If I put this in, I also get an error.

Book.find(1).reviews.each do |r|

?> puts review.created_reviews.name

end

NameError: undefined local variable or method `review' for
#<Object:0x18fa38>
       from (irb):11

Close, try:
Book.find(1).reviews.each do |review|
then the block will have a variable named review (rather than the r in your first attempt)

Clearly I'm lost and confused. Thanks for helping out this new ruby
girl.

Be aware that your confusion seems to be a mix of Rails (specifically, ActiveRecord) conventions and Ruby syntax.

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

Rob Biedenharn wrote:

Be aware that your confusion seems to be a mix of Rails (specifically,
ActiveRecord) conventions and Ruby syntax.

Yes, I'm still new to this. Thank you so much for your patience and
great help.

I've got it all working now!