12.1.2 Ассоциации пользователь/взаимоотношение
Прежде чем приступить к реализации читателей и читаемых, нам вначале необходимо установить ассоциацию между пользователями и взаимоотношниями. Пользователь has_many
(имеет_много) взаимоотношений, и, так как взаимоотношения включают двух пользователей — взаимоотношение belongs_to
(принадлежит_к) читающим и читаемым пользователям.
Как и с микросообщениями в Разделе 11.1.2, мы будем создавать новые взаимоотношения используя ассоциацию, с помощью такого кода
user.relationships.create(:followed_id => ...)
Мы начнем с теста, показанного в Листинге 12.3, который устанавливает переменную экземпляра @relationships
(используется ниже) и проверяет, что она может быть сохранена используя save!
. Как и create!
, метод save!
вызывает исключение в случае неудачного сохранения; сравните это с использованием create!
в Листинге 11.4.
save!
. spec/models/relationship_spec.rb
require 'spec_helper'
describe Relationship do
before(:each) do
@follower = Factory(:user)
@followed = Factory(:user, :email => Factory.next(:email))
@relationship = @follower.relationships.build(:followed_id => @followed.id)
end
it "should create a new instance given valid attributes" do
@relationship.save!
end
end
Мы также должны протестировать модель User на relationships
атрибут, как показано в Листинге 12.4.
user.relationships
атрибут. spec/models/user_spec.rb
describe User do
.
.
.
describe "relationships" do
before(:each) do
@user = User.create!(@attr)
@followed = Factory(:user)
end
it "should have a relationships method" do
@user.should respond_to(:relationships)
end
end
end
На этом этапе вы могли бы ожидать код приложения, как в Разделе 11.1.2, и он аналогичен, но есть одно существенное отличие: в случае с моделью Micropost мы могли бы сказать
class Micropost < ActiveRecord::Base
belongs_to :user
.
.
.
end
и
class User < ActiveRecord::Base
has_many :microposts
.
.
.
end
так как в microposts
есть атрибут user_id
для идентификации пользователя (Раздел 11.1.1). Id используемый таким способом для связи двух таблиц базы данных, известен как внешний ключ, и когда внешним ключом для объекта модели User является user_id
, Rails может вывести ассоциацию автоматически: по умолчанию, Rails ожидает внешний ключ в форме <class>_id
, где <class>
является строчной версией имени класса.5 В данном случае, несмотря на то, что мы по прежнему имеем дело с пользователями, они теперь отождествляются с внешним ключом follower_id
, поэтому мы должны сообщить об этом Rails, как показано в Листинге 12.5.6
has_many
ассоциации пользователь/взаимоотношение. app/models/user.rb
class User < ActiveRecord::Base
.
.
.
has_many :microposts, :dependent => :destroy
has_many :relationships, :foreign_key => "follower_id",
:dependent => :destroy
.
.
.
end
(Поскольку уничтожение пользователя должно также уничтожить его взаимоотношения мы пошли еще дальше и добавили :dependent => :destroy
к ассоциации; написание теста на это останется в качестве упражнения (Раздел 12.5).) На данный момент, тест ассоциации из Листинга 12.3 и Листинга 12.4 должен пройти.
Как и у модели Micropost, у Relationship модели есть belongs_to
взаимоотношения с пользователями; в данном случае, объект взаимоотношение принадлежит к обоим follower
и followed
пользователям, что мы и тестируем в Листинге 12.6.
belongs_to
ассоциации пользователь/взаимоотношения. spec/models/relationship_spec.rb
describe Relationship do
.
.
.
describe "follow methods" do
before(:each) do
@relationship.save
end
it "should have a follower attribute" do
@relationship.should respond_to(:follower)
end
it "should have the right follower" do
@relationship.follower.should == @follower
end
it "should have a followed attribute" do
@relationship.should respond_to(:followed)
end
it "should have the right followed user" do
@relationship.followed.should == @followed
end
end
end
Чтобы написать код приложения, мы определяем belongs_to
взаимоотношения как обычно. Rails выводит названия внешних ключей из соответствующих символов (т.e., follower_id
из :follower
, и followed_id
из :followed
), но, так как нет ни Followed ни Follower моделей, мы должны снабдить их именем класса User
. Результат показан в Листинге 12.7.
belongs_to
ассоциаций к модели Relationship. app/models/relationship.rb
class Relationship < ActiveRecord::Base
attr_accessible :followed_id
belongs_to :follower, :class_name => "User"
belongs_to :followed, :class_name => "User"
end
Ассоциация followed
на самом деле не потребуется до Раздела 12.1.5, но параллельность структуры читатели/читаемые лучше видна при одновременной реализации.