gabriel
gabriel

Reputation: 345

Ruby on rails objects associations

I have two objects - User and Reviews. One User can write many reviews, but one review can be written by one user. Every user has a picture. I have:

class Review < ActiveRecord::Base
   belongs_to :user
end

class User < ActiveRecord::Base
  has_many :reviews
end

Why can't I do the following?

review.user.picture

Upvotes: 0

Views: 63

Answers (3)

Richard Peck
Richard Peck

Reputation: 76784

Method

The bottom line is your picture method will not be present in your user model

You can either use an instance method to create some functionality in your User model, use an ActiveRecord Association, or use something like Paperclip to provide an appended object on your user object


Association

You'll need to create the correct association for your review & picture objects -

#app/models/user.rb
Class Review < ActiveRecord::Base
   has_many :reviews
   has_one  :picture
end

#app/models/picture.rb
Class Picture < ActiveRecord::Base
   belongs_to :user
end

This will allow you to call:

@review = Review.find params[:id]
@picture = @review.user.picture 

A bonus tip for this is if you wanted to ensure compatibility with the law of dementer, you could use the delegate method in your user model:

#app/models/user.rb
Class User < ActiveRecord::Base
   ...
   delegate :attribute, to: :picture, prefix: true
end

This will allow you to call the likes of:

@review.user.picture_name

Paperclip

If you're using a picture model to store images, you may wish to use the likes of Paperclip to give you the ability to use the functionality of images in your Picture model:

#app/models/user.rb
Class User < ActiveRecord::Base
    ...
    delegate :url, to: :picture
end

#app/models/picture.rb
Class Picture < ActiveRecord::Base
    has_attached_file :picture
end

These will all help you. Using this answer with Иван Бишевац's will help you profusely :)

Upvotes: 0

JeffD23
JeffD23

Reputation: 9318

Based on the info you provided, I'm assuming you still need to set up a foreign key in the database. The database migration for the the reviews table should look similar to this:

class CreateReviews < ActiveRecord::Migration
 def change
  create_table :reviews do |t|
   t.integer :user_id
   t.timestamps
  end
   add_index :reviews, :user_id
  end
end 

Then you would be able to add a related user_id to a new review object. For instance, in rails console:

Review.new(user_id: 1)

Assuming that you defined picture as a column in your User table, you should be able to run review.user.picture without any issues.

Upvotes: 0

Иван Бишевац
Иван Бишевац

Reputation: 14701

You have to establish has_one/belongs_to associations on user/picture models and of course to have appropriate database migrations (foreign key user_id on picture table and foreign key user_id on review table).

Models look like:

class Review < ActiveRecord::Base
   belongs_to :user
end

class User < ActiveRecord::Base
  has_many :reviews
  has_one :picture
end

class Picture
  belongs_to :user
end

To try it, first create data in rails console:

user = User.create
review = Review.create user: user
picture = Picture.create user: user

Now you can find user picture if you have only reference to review object. Exit console and run again and type:

review = Review.last
review.user.picture

It returns picture object.

More info:

http://guides.rubyonrails.org/association_basics.html#choosing-between-belongs-to-and-has-one

Upvotes: 2

Related Questions