ruby on Rails,如何实现关系

发布于 2024-12-14 01:08:57 字数 1520 浏览 5 评论 0原文

我被这个应用程序困住了) 我有 3 个模型 - 用户、照片和点赞 用户将登录、查看照片并将其标记为“喜欢”或“不喜欢”。 这是我的数据库架构,为brewity跳过了无关紧要的字段:

  create_table "likes", :force => true do |t|
    t.integer  "oid"       # oid is photos.id
    t.integer  "user_id"   # user who liked this photo
    t.boolean  "mark",       :default => true
  end

  create_table "photos", :force => true do |t|
    t.string   "photo"   #filename of the photo
  end

  create_table "users", :force => true do |t|
    t.string   "firstname", 
    t.string   "lastname",  
    t.string   "email",   
  end

这是模型:

class Photo < ActiveRecord::Base    
  has_many  :likes,  :foreign_key => 'oid'
end

class Like < ActiveRecord::Base
  belongs_to :photo
end

class User < ActiveRecord::Base
  has_many  :likes, :through => :photos
end

一张照片每个用户有一个标记。即用户不能“喜欢”照片两次或多次。

我希望用户重新登录后能够看到他们对哪些照片进行了评估。

现在,我选择带有以下声明的照片: @photos = Photo.limit(30).offset(0) 然后在模板中: <%= photo.likes.where("user_id=#{current_user.id}") %> 此后,我有 30 多个 SQL 查询,或者换句话说,N+1 问题。

避免此问题的一种方法是在选择照片时添加“喜欢”。

 @photos = Photo.includes(:likes ).limit(30).offset(0)

但这将包括所有用户对照片的所有点赞,并对应用程序的性能产生不利影响。另外,我必须提取当前用户的记录。

第二个选项是创建动态关系

class User < ActiveRecord::Base
  has_many  :likes, :through => :photos, :conditions => "user_id = current_user.id"
end

对于此选项,我必须将 current_user.id 从控制器传递到模型,这对我来说看起来不正确。

请帮忙解决这个问题

I'm stuck with this application )
I have 3 models - User, Photo and Like
Users will log in, view photos and mark them "like" or "dislike".
Here's my DB schema, insignificant fields skipped for brewity:

  create_table "likes", :force => true do |t|
    t.integer  "oid"       # oid is photos.id
    t.integer  "user_id"   # user who liked this photo
    t.boolean  "mark",       :default => true
  end

  create_table "photos", :force => true do |t|
    t.string   "photo"   #filename of the photo
  end

  create_table "users", :force => true do |t|
    t.string   "firstname", 
    t.string   "lastname",  
    t.string   "email",   
  end

Here's models:

class Photo < ActiveRecord::Base    
  has_many  :likes,  :foreign_key => 'oid'
end

class Like < ActiveRecord::Base
  belongs_to :photo
end

class User < ActiveRecord::Base
  has_many  :likes, :through => :photos
end

One photo will have one mark per user. i.e. user can't 'like' photo twice or more.

I want users to be able to see which photos they have given estimates after they relogin.

For now, I select photos with this statement:
@photos = Photo.limit(30).offset(0)
then in template:
<%= photo.likes.where("user_id=#{current_user.id}") %>
After this, I have 30+ SQL queries, or, in other words, N+1 problem.

One option to avoid the problem is to include likes when selecting photos.

 @photos = Photo.includes(:likes ).limit(30).offset(0)

But this will include ALL likes for photo, from all users, and adversely affect the performance of application. Plus I'll have to extract record for current user.

Second option is to create dynamic relation

class User < ActiveRecord::Base
  has_many  :likes, :through => :photos, :conditions => "user_id = current_user.id"
end

For this option, I'll have to pass current_user.id from controller to model, which doesn't look correct for me.

Please help to solve this

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

少年亿悲伤 2024-12-21 01:08:57

首先,这是一个设计问题。想想看:“喜欢”是用户和照片之间的某种纽带。只要大声说出来:“一张照片可能被很多用户喜欢;一个用户可能喜欢很多照片”。

您的 Like 模型应该位于 PhotoUser 模型之间,这不是很清楚吗?

.----------.1   0..*.----------.0..*    1.----------.
|  users   |<-------|  likes   |-------->| photos   |
'----------'        '----------'         '----------'

class User < ActiveRecord::Base
  has_many :likes
  has_many :liked_photos, through: :likes, class: 'Photo'
end

class Like < ActiveRecord::Base
  belongs_to :user
  belongs_to :photo
  # this will ensure that your users can only like a photo once.
  # you can also add a unique index to the two columns using 
  # add_index in a migration for more safety and performance.
  validates_uniqueness_of [:user, :photo]
end

class Photo < ActiveRecord::Base
  has_many :likes
  has_many :liking_users, through: :likes, class: 'User'
end

现在,您只需执行以下操作即可高效检索相关图片:

@user   = User.includes( likes: :photos ).find( current_user.id )
@photos = @user.liked_photos

First of all, this is a design issue. Think about this : "like" is some kind of bond between a user and a photo. Just say it loud : "a photo may be liked by many users ; a user may like many photos".

Isn't it clear that your Like model should stand between your Photo and User model ?

.----------.1   0..*.----------.0..*    1.----------.
|  users   |<-------|  likes   |-------->| photos   |
'----------'        '----------'         '----------'

class User < ActiveRecord::Base
  has_many :likes
  has_many :liked_photos, through: :likes, class: 'Photo'
end

class Like < ActiveRecord::Base
  belongs_to :user
  belongs_to :photo
  # this will ensure that your users can only like a photo once.
  # you can also add a unique index to the two columns using 
  # add_index in a migration for more safety and performance.
  validates_uniqueness_of [:user, :photo]
end

class Photo < ActiveRecord::Base
  has_many :likes
  has_many :liking_users, through: :likes, class: 'User'
end

Now, you just have to do this to retrieve efficiently the relevant pictures:

@user   = User.includes( likes: :photos ).find( current_user.id )
@photos = @user.liked_photos
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文