简体   繁体   中英

How do I connect columns in two Ruby on Rails models?

I'm re-writing http://bngb.org as a Rails project (my first). I've gone through Michael Hartl's tutorial. I've created Group and User models. A group belongs_to a user and a user has_one group, which is destroyed with the user.

The contact email address for each group should be that of the user who owns the group, and should change when it changes. I see that I can retrieve the address with group.user.email in my views, but it looks like this makes a database call each time instead of using cached data. What's the correct way to have a group.email column which is linked to user.email ? Can I do it with what I have, or do I need a third table linked by has_one through: ?

Thanks very much for your help!
Jeff Covey

You can use ActiveRecord's after_find callback to add that to an attribute. Here's an example:

class Group < ApplicationRecord
  belongs_to :user
  attr_accessor :email

  after_find :attach_email

  private

  def attach_email
    self.email = user.email
  end
end

It will make the initial database call to user when the object is retrieved from the database, and then save it as an attribute so all subsequent calls do not need to hit the DB.

You can use delegates .

class Group < ActiveRecord::Base
  belongs_to :user
  delegate :email, to: :user, allow_nil: true
end

It'll only make call to user table the first time you use group.email and will be cached for the subsequent calls.

Anurag Aryan's answer suggesting delegate is a good start! Given that Rails will cache results for your database queries, it might be good enough for you. Take a look at these docs to see what Rails does to avoid querying the DB . Have a close look at your server logs too and look for the word CACHE at the beginning of your queries.

Here is a sample (from one of my apps) of what to look for:

Unit Load (0.2ms)  SELECT  "units".* FROM "units" WHERE "units"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
↳ app/views/guests/reservations/_reservation.html.erb:5
CACHE Unit Load (0.0ms)  SELECT  "units".* FROM "units" WHERE "units"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
↳ app/views/guests/reservations/_reservation.html.erb:5

Notice the word CACHE on the third line? That's Rails reporting that the query didn't hit the DB. If you want to avoid this additional query entirely use eager_load when getting the groups. I think in your case, this will look like:

@groups = Group.eager_load(:user).all

In your logs you should see that Rails will construct a query that joins your Groups and Users without a subsequent query.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM