Как я могу определить несколько has_and_belongs_to_many в Rails? - PullRequest
2 голосов
/ 29 марта 2012

У меня две модели: пользователь, артикул

Пользователю может понравиться или не понравиться множество статей, а статья может понравиться или не понравиться многим пользователям. Поэтому мне нужно выстроить отношения между многими.

В рельсах, я думаю, мне нужно использовать has_and_belongs_to_many ..

Я думаю, что структура кода выглядит следующим образом:

class User
    has_and_belongs_to_many :liked_articles
    has_and_belongs_to_many :disliked_articles
end

class Article
    has_and_belongs_to_many :liking_users
    has_and_belongs_to_many :disliking_users
end

Конечно, приведенный выше код не работает.

Но я не знаю, что такое правильный код. Кто может мне помочь?

Обновлен:

Я придумал такой код:

class User
    has_and_belongs_to_many :liked_articles, :class_name => 'Article', :join_table => 'articles_users_like', :uniq => true
    has_and_belongs_to_many :disliked_articles, :class_name => 'Article', :join_table => 'articles_users_dislike', :uniq => true
end

class Article
    has_and_belongs_to_many :liking_users, :class_name => 'User', :join_table => 'articles_users_like', :uniq => true
    has_and_belongs_to_many :disliking_users, :class_name => 'User', :join_table => 'articles_users_dislike', :uniq => true
end

Я думаю, что это будет работать.

но, как сказали и Питер Собот, и Джон Макинтош, в настоящее время has_many: сквозной является более предпочтительным. Ты можешь сказать мне, почему? Последний логически более понятен, чем has_and_belongs_to?

Ответы [ 2 ]

4 голосов
/ 29 марта 2012

Эти методы привязки привязаны к моделям. Если у вас нет модели Liking_User и Disliking_User, это явно не сработает. Кроме того, я считаю, что вы идете по этому неправильному пути.

Давайте разберем эту проблему на мгновение. У вас есть User и Article. Ваши Article должны иметь функциональность, чтобы они не нравились и нравились Users, правильно? Я собираюсь визуализировать это как система репутации SO / Reddit и предположить, что User может как или не нравится и Article один раз. Для этого я бы создал отдельную модель для голосования под названием Votes и связал бы ее вместе с has_many, :through ассоциацией.

User.rb

  class User < ActiveRecord::Base
     has_many :votes
     has_many :articles, :through => :votes
   end

Article.rb

  class Article < ActiveRecord::Base
     has_many :votes
     has_many :users, :through => :votes
  end

Vote.rb

  class Vote < ActiveRecord::Base
     belongs_to :user
     belongs_to :article
  end

Теперь, когда эти ассоциации установлены, модели будут искать несколько полей в базе данных. Структура должна выглядеть примерно так:

Users
+----+-----------+
| id | user_name | 
+----+-----------+    

Articles
+----+--------+
| id |  title |
+----+--------+

Votes
+----+----------+------------+-------+
| id |  user_id | article_id | value |
+----+----------+------------+-------+

Это завершает ассоциацию, давая модели идентификатор для ссылки. Теперь вы можете наблюдать магию рельсов при создании этой записи для голосования ...

class ArticlesController < ApplicationController
  def like
    @article = Article.find(params[:article_id])
    @article.votes.create(:user_id => current_user, :value => 1)

    respond_to do |format|
      if @article.save
        format.html { redirect_to @article, notice: 'Article was successfully liked.' }
        format.json { head :no_content }
      else
        format.html { redirect_to @article, notice: 'Article was unsuccessfully liked.' }
        format.json { render json: @article.errors, status: :unprocessable_entity }
      end
    end

  end
end

РЕДАКТИРОВАТЬ: Согласно вашему комментарию, отношения has_and_belongs_to_many и has_many :through очень похожи ... У вас есть две модели и таблица объединения держать данные ссылки. Разница между ними заключается в том, что для has_many :through требуется третья модель, с которой взаимодействуют (например, пользователи / статьи / голоса).

Причина, по которой has_many :through более широко рекомендуется, заключается в том, что он более гибкий, и вам предоставляется больше возможностей для работы, чем к последнему. В вашем случае вы должны создать эти отношения, потому что вам нужна третья модель для подсчета голосов.

Логика, которой вы руководствуетесь сейчас, устанавливает принципала для создания четырех моделей и требует обновления конкретных моделей на основе действий, которые пользователь хочет предпринять. Это абсолютно не рельсовый (или любой логический) способ ведения дел. Сохраняй это простым.

Руководства по Ruby on Rails: Руководство по ассоциациям активных записей

3 голосов
/ 29 марта 2012

has_and_belongs_to_many в настоящее время считается несколько устаревшим - вы, вероятно, захотите использовать has_many :through в этом случае. Попробуйте использовать одну таблицу для «голосов» и сделать что-то вроде этого:

class User < ActiveRecord:Base
    has_many :votes
    has_many :articles, :through => :votes
end

class Article < ActiveRecord:Base
    has_many :votes
    has_many :users, :through => :votes
end

class Vote < ActiveRecord:Base
    belongs_to :article
    belongs_to :user
end

Затем можно добавить поле «знак» в vote, чтобы показать, является ли это повышением или понижением, и затем отфильтровать его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...