Rails моделирует отношения

#ruby-on-rails #ruby #ruby-on-rails-3 #rails-migrations #rails-models

#ruby-on-rails #ruby #ruby-on-rails-3 #rails-миграции #rails-модели

Вопрос:

Привет, коллеги-разработчики! Недавно я играл с Rails 3.0 и после довольно продолжительных исследований я вроде как застрял. Я хочу знать, какой подход или решение является лучшим в моем случае (я пока не смог найти ответ). Итак, то, чего я пытаюсь достичь, просто и прямолинейно.

Я хочу сделать что-то вроде этого:

 class User < ActiveRecord::Base
    has_many :feeds
    has_many :casts, :through => :feeds
end

class Feed < ActiveRecord::Base
  has_many :users
  has_many :casts
end

class Cast < ActiveRecord::Base
  belongs_to :feed
end
  

Итак, в конце мне нужны такие методы, как User.first.feeds, чтобы получить все каналы пользователя и User.first.casts, чтобы получить все касты пользователя через его / ее каналы. Также было бы неплохо иметь Feed.first.casts и Feed.first.users. Довольно просто, верно, но мне также сложно создавать миграции для того, чего я пытаюсь достичь.

Я знаю, что приведенный выше код не будет работать — я играл с ним, так что это всего лишь концепция того, чего я пытаюсь достичь.

В основном мои вопросы таковы: должен ли я каким-то образом делать это через join model или использовать области видимости?(также не могли бы вы привести фрагмент кода) и как мне выполнить миграцию для этого?

Спасибо и извините, что я не смог найти много информации в Интернете относительно этого простого случая.

Редактировать: has_and_belongs_to_many для User и Feed в моем случае не будет работать, потому что это не позволит мне иметь @user.casts, это дает только @user.feeds и @feed.users

Ответ №1:

То, что вы хотите, — это отношения «многие ко многим» между пользователем и каналом.

Вам понадобится что-то подобное в вашем коде, чтобы отношения пользователя и канала работали.

 class User < ActiveRecord::Base
  has_and_belongs_to_many :feeds
end

class Feed < ActiveRecord::Base
  has_and_belongs_to_many :users
end
  

Вы можете прочитать больше об этом в руководствах по Rails — http://guides.rubyonrails.org/association_basics.html#the-has_and_belongs_to_many-association

Возможно, вы также захотите рассмотреть использование has_many : through с промежуточной моделью для этого (объясняется здесь http://guides.rubyonrails.org/association_basics.html#choosing-between-has_many-through-and-has_and_belongs_to_many ) если вы хотите сохранить какие-либо метаданные для записи связи пользовательского канала.

Редактировать: мне удалось добиться аналогичной настройки, работающей как на 3.0, так и на 3.1 (используя has_many :through).

Вот содержимое моих моделей.

 ➜  app  cat app/models/*
class Cast < ActiveRecord::Base
  belongs_to :feed
end

class Feed < ActiveRecord::Base
  has_many :subscriptions
  has_many :casts
end

class Subscription < ActiveRecord::Base
  belongs_to :user
  belongs_to :feed
end

class User < ActiveRecord::Base
  has_many :subscriptions
  has_many :feeds, :through => :subscriptions

  # For 3.1
  has_many :casts, :through => :feeds
  # For 3.0
  def casts
    Cast.joins(:feed => :subscriptions).where("subscriptions.user_id" => self.id)
  end
end
  

и вот миграции, которые я использовал

 ➜  app  cat db/migrate/*
class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.string :name

      t.timestamps
    end
  end

  def self.down
    drop_table :users
  end
end
class CreateFeeds < ActiveRecord::Migration
  def self.up
    create_table :feeds do |t|
      t.string :name

      t.timestamps
    end
  end

  def self.down
    drop_table :feeds
  end
end
class CreateCasts < ActiveRecord::Migration
  def self.up
    create_table :casts do |t|
      t.string :name
      t.integer :feed_id

      t.timestamps
    end
  end

  def self.down
    drop_table :casts
  end
end
class CreateSubscriptions < ActiveRecord::Migration
  def self.up
    create_table :subscriptions do |t|
      t.integer :feed_id
      t.integer :user_id
    end
  end

  def self.down
    drop_table :subscriptions
  end
end
  

Комментарии:

1. Я прочитал руководства red Rails по этому поводу сверху донизу и не нашел ответа. Я уже пробовал has_and_belongs_to_many, и это просто дает мне методы @user.feeds и @feed.users. Что мне действительно нужно, так это в дополнение к этим двум иметь @user.casts, которые будут принадлежать этому пользователю через его каналы.

2. Спасибо, я проверил с Rails 3.0, и это работает отлично. Я получил свой метод @user.casts. И последнее, чего мне не хватает — @feed.users, я думаю, мне нужно что-то добавить к модели подписки / миграции, верно?

3. Я не тестировал это, но добавление has_many :users, :through => :subscriptions в модель Feed должно сработать. Нет необходимости в какой-либо миграции.

Ответ №2:

В http://railscasts.com/episodes/265-rails-3-1-overview Райан Бейтс говорит, что в rails 3.1 есть поддержка связанных вызовов has_many :through. Это невозможно в версии 3.0

Комментарии:

1. Хорошо, итак, в этом случае у меня есть два вопроса: как достичь чего-то подобного в 3.0 (используя области видимости или что-то в этом роде) и как мне выполнить миграции, если я решу перейти на got с 3.1? Спасибо.