Рубин на рельсах, как реализовать отношения - PullRequest
0 голосов
/ 07 ноября 2011

Я застрял с этим приложением) У меня есть 3 модели: пользователь, фотография и лайк Пользователи будут входить в систему, просматривать фотографии и отмечать их как «нравится» или «не нравится».Вот моя схема БД, для пивоварения пропущены незначительные поля:

  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 из контроллера вмодель, которая мне не подходит.

Пожалуйста, помогите решить эту проблему

1 Ответ

3 голосов
/ 08 ноября 2011

Прежде всего, это проблема дизайна .Подумайте об этом: «нравится» - это какая-то связь между пользователем и фотографией.Просто скажи это громко: «фотография может понравиться многим пользователям; пользователю может понравиться много фотографий».

Разве не ясно, что ваша модель Like должна стоять между вашей моделью Photo и User?

.----------.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
...