不止一个人:通过?

时间:2015-03-14 19:54:29

标签: ruby-on-rails ruby activerecord has-many-through rails-models

因此。我有用户和电影。用户观看了一些电影而不是其他电影。我想表达这样的关系: users and movies

注意:

  • 不确定是否重要;但是电影不能 连接到用户;它们可以独立存在(即电影1与用户2没有关系)。用户也可以独立存在;他们不必观看或看过电影(这里没有图片,但是你明白了)
  • 一部用户可以观看一部电影,但另一部用户无法观看(灰色与黑色连接)

我最初的反应是这是has_many :through关系,例如:

/models/user.rb:

def User
    has_many :movies, :through => :unwatched_movies
    has_many :movies, :through => :watched_movies
end

/models/movie.rb:

def Movie
    has_many :users, :through => :unwatched_movies
    has_many :users, :through => :watched_movies
end

但首先,该代码肯定不起作用......

我希望能够查询u.unwatched_movies(其中uUser的一个实例,但似乎与上述情况无关。< / p>

我觉得这与:source:as有关......但我感觉有点失落。我是否正确地认为这是一个3级层次结构,我需要UserUnwatchedMovieList / WatchedMovieListMovie的模型? This question感觉非常接近,但我似乎无法在这种情况下使其发挥作用。

有关如何编写这些模型和迁移的任何帮助都会非常有用。谢谢!

3 个答案:

答案 0 :(得分:1)

你正试图建立一种遗漏关系 - “无与伦比的电影”。这不是一个好主意,你应该建立一个电影观看的历史(这是watched_movies)但然后为了无人看,你会想找到所有电影减去观看电影。然后将其粘贴在User中的函数中,如下所示:

def unwatched_movies
  Movie.where("id NOT IN ?", self.watched_movies.collect(&:movie_id))
end

答案 1 :(得分:1)

这是我的解决方案

创建这些模型

class User < ActiveRecord::Base
    has_many :user_movies
    # Use a block to add extensions 
    has_many :movies, through: :user_movies, source: 'movie' do
        # this is an extension
        def watched
            where('user_movies.watched = ?', true)
        end
        def unwatched
            where('user_movies.watched = ?', false)
        end
    end
end

class Movie < ActiveRecord::Base
    has_many :user_movies
    has_many :watchers, through: :user_movies, source: :user do
        # users who is an effective watcher 
        def watchers
            where('user_movies.watched = ?', true)
        end
        # users how marked it but did not watch it yet
        def markers
            where('user_movies.watched = ?', false)
        end
    end
end

class UserMovie < ActiveRecord::Base
  belongs_to :user
  belongs_to :movie
end

class CreateUserMovies < ActiveRecord::Migration
  def change
    create_table :user_movies do |t|
      t.belongs_to :user, index: true
      t.belongs_to :movie, index: true
      t.boolean :watched, default: false, null: false

      t.timestamps null: false
    end
    add_foreign_key :user_movies, :users
    add_foreign_key :user_movies, :movies
  end
end

然后查询

@user = User.first
@user.movies.watched
@user.movies.unwatched

@movie = Movie.first
@movie.watchers.watchers
@movie.watchers.markers

答案 2 :(得分:0)

以下一组关联应涵盖您能够明确标记已观看和未观看的电影的用例。它使用名为user_movies的联接表,其中只包含以下字段:user_id, movie_id, and watched

class User
  has_many :unwatched_user_movies, -> { where(watched: false) }, class_name: 'UserMovie'
  has_many :unwatched_movies, through: :unwatched_user_movies, class_name: 'Movie'

  has_many :watched_user_movies, -> { where(watched: true) }, class_name: 'UserMovie'
  has_many :watched_movies, through: :watched_user_movies, class_name: 'Movie'
end

class UserMovie
  belongs_to :movie
  belongs_to :user
end

class Movie
  has_many :user_movies
end