`
peryt
  • 浏览: 55268 次
  • 来自: ...
最近访客 更多访客>>
社区版块
存档分类
最新评论
  • waiting: 既然都指定了dataType为'script'那就不必特别在b ...
    jQuery

12. following user, 12.1 relationship model

 
阅读更多

1. we need to use a relationships table to stand for the following relationship:

 

has_many :following, :through => :relationships, :source => "followed_id"

 2. then 

 

$ rails generate model Relationship follower_id:integer followed_id:integer

 3. we need to add index to the table

 

add_index :relationships, :follower_id
    add_index :relationships, :followed_id
    add_index :relationships, [:follower_id, :followed_id], :unique => true

 note the last index is a composite one, and is unique.

 

4. then rake db:migrate

rake db:test:prepare

 

5. we will follow a good practice here:

remember, it is good to define attr_accessible for every model to avoid mass assignment to some attrs that you don't want user to touch.

 

so here, we know we only want user to modify the followed_id, never the follower_id.

so

 

attr_accessible :followed_id

 

6. how to create a relationship:

we should use the user association to create relationship:

 

user.relationships.create!(:followed_id => "")

 

7. below is the test spec of relationship model:

 

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

note, @relationship.save! will throw an exception if fail.

we user @follower.relationships.build() to create a relationship.

 

in the user model, we also need to test it respond to the relationships method.

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

 

8. when we define

 

class User
  has_many :microposts
end
class Micropost
  belongs_to :user
end

 because microposts table has a user_id to identify the user, so this is a foreign key, which is connecting two tables, and when the foreign key for a user object is user_id, rails can infer the association auto, by  default, rails expects a foreign key of user_id, where user is the lower case of class User.

 

but now, although we are dealing with users, they are now identified with the foreign key follower_id, so we have to tell rails, that follower_id is a foreign key.

 

 

class User
  has_many :relationships, :foreign_key => "follower_id", :dependent = :destroy
end
 

 

9. next, the relationship should belong to users, one relationship belong to 2 users.

a follower and a followed user.

 

let write test:

 

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

 

next, we will make this test pass:

 

  belongs_to :follower, :class_name => "User"
  belongs_to :followed, :class_name => "User"

 

10. next we will add some validations to the relationship model:

the test is:

 

describe Relationship do
  .
  .
  .
  describe "validations" do

    it "should require a follower_id" do
      @relationship.follower_id = nil
      @relationship.should_not be_valid
    end

    it "should require a followed_id" do
      @relationship.followed_id = nil
      @relationship.should_not be_valid
    end
  end
end

 next, let's add the validations:

 

validates :follower_id, :presence => true
  validates :followed_id, :presence => true
 

11. following:

the user object should respond to following method:

 

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

    it "should have a following method" do
      @user.should respond_to(:following)
    end
  end
end

 to make it pass, we need this line of code:

 

has_many :followeds, :through => :relationships

 rails then can deduce it should use "followed_id" assemble an array.

 

but as you see, followeds is awkward english, so we want to overwrite the default name:

has_many :following, :through => :relationships, :source => :followed
then we will add some utility methods:
user.follow!(other_user)   ===> it will throw an exception if failure.
user.following?(other_user)
but before that, we will write test to see what the two method do:
describe User do
  .
  .
  .
  describe "relationships" do
    .
    .
    .
    it "should have a following? method" do
      @user.should respond_to(:following?)
    end

    it "should have a follow! method" do
      @user.should respond_to(:follow!)
    end

    it "should follow another user" do
      @user.follow!(@followed)
      @user.should be_following(@followed)
    end

    it "should include the followed user in the following array" do
      @user.follow!(@followed)
      @user.following.should include(@followed)
    end
  end
end
note:
  @user.following.should include(@followed)
is equivalent with:
@user.following.include?(@followed).should be_true
 but more cleare.

next, we can implement the two methods:
def following?(followed)
    relationships.find_by_followed_id(followed)
  end

  def follow!(followed)
    relationships.create!(:followed_id => followed.id)
  end
  of course, we also need unfollow! method.
the test is:
it "should have an unfollow! method" do
      @user.should respond_to :unfollow!
    end
    it "should unfollow a user" do
      @user.follow!(@followed)
      @user.unfollow!(@followed)
      @user.should_not be_following(@followed)
    end
 the code of unfollow! is straight forward.
def unfollow!(followed)
    relationships.find_by_followed_id(followed).destroy
  end
 
12. followers:
the part is tricky, let's write some test first:
it "should have a reverse_relationships method" do
      @user.should respond_to(:reverse_relationships)
    end

    it "should have a followers method" do
      @user.should respond_to(:followers)
    end

    it "should include the follower in the followers array" do
      @user.follow!(@followed)
      @followed.followers.should include(@user)
    end
 we won't use a new table to hold the followers, we will use the same table, but with different relationships:

has_many :reverse_relationships, :foreign_key => "followed_id", :class_name => "Relationship", :dependent => :destroy
 note, the foreign key is different, and we need to specify the class name, or rails will try to find 
ReverseRelationship class.

then we can have:
has_many :followers, :through => :reverse_relationships, :source => :follower
 
ok,  we finally done with data model of relationship and following and followers.

分享到:
评论

相关推荐

    Feedback.Control.for.a.Path.Following.Robotic.Car

    Then the path coordinate model is converted into chained form and a controller is given to perform path following. The path coordinate model introduces a new parameter to the system: the curvature of...

    MATLAB_Program.rar_car following model_nearesttt3_基因算法_跟车_跟车模型

    首先,"car_following_model"是指汽车跟车模型,这是交通流理论中的一个重要组成部分,用来描述一辆车如何根据前方车辆的运动状态调整自己的速度和行驶距离。这类模型通常包括驾驶员的反应时间、车辆的动力学特性...

    SSD7 选择题。Multiple-Choice

    In the Entity-Relationship model, the degree of a relationship specifies which of the following? (a) The cardinality ratio of the relationship (b) The number of integrity constraints required to ...

    ros by example for indigo volume 2

    3.4 A Patrol Bot Example.........................................................................................12 3.5 The Patrol Bot using a Standard Script.............................................

    C# Game Programming Cookbook for Unity 3D - 2014

    2.2.1 BaseGameController.cs.....................................12 2.2.1.1 Script Breakdown................................14 viii Contents 2.2.2 Scene Manager............................................

    Manning.Spring.in.Action.4th.Edition.2014.11.epub

    Chapter 12. Working with NoSQL databases 12.1. Persisting documents with MongoDB 12.1.1. Enabling MongoDB 12.1.2. Annotating model types for MongoDB persistence 12.1.3. Accessing MongoDB with Mongo...

    算法上机!!

    , 3, 15, 12, 7, 2> , 2, 4, 15, 20, 5> Longest Common Subsequence (LCS). The following are some instances. X: xzyzzyx Y: zxyyzxz X:MAEEEVAKLEKHLMLLRQEYVKLQKKLAETEKRCALLAAQANKESSSESFISRLLAIVAD Y:...

    Django2 By Example中文(6-13)_精排目录

    following = user.following.all() # 更多逻辑... ``` #### 使用 Redis 存储和检索数据 对于需要高速读写操作的场景,如行为流中的实时更新,可以考虑使用 Redis 这样的键值存储数据库。Redis 提供了丰富的数据...

    Ad Muncher 4.94 简体中文增强版.exe

    超强的电脑去广告软件,可以自定义规则 Licensor: Murray Hurps Software Pty Ltd, Australia Permission to use this software is conditional upon the user agreeing to the terms set ...12. This agreement shall

    Cypress电容触摸

    // The following changes were made to the default settings in the Device Editor: // // Select User Modules // o Select CSD_1 & SPIS_1 user modules. // o In this example, these UMs are renamed as...

    a project model for the FreeBSD Project.7z

    The core utilities, known as userland, provide the interface that identifies FreeBSD, both user interface, shared libraries and external interfaces to connecting clients. Currently, 162 people are ...

    Relational.Database.Management.Systems

    It covers the following chapters: Database Systems,Database Systems Concepts and Architecture, Data Modelling Using ER Model, Relational Model, Normalization, Database Access and Security, SQL Using ...

    CyUSB3.SYS和CyAPI.LIB的源代码

    Following projects source code is included in this package. 1. CyAPI C++ Static Library. 2. CyUSB C# DLL. Following directories are included this package. 1.CyAPI => library => cpp This directory ...

    darknet-ros-master.zip

    The pre-trained model of the convolutional neural network is able to detect pre-trained classes including the data set from VOC and COCO, or you can also create a network with your own detection ...

    健康医院门诊在线挂号系统论文.doc

    Following the traditional software development process, it first selects suitable development platforms and languages, conducts demand analysis, and designs the database structure. Based on the ...

    Improving the load-following capability of a solid oxide fuel cell system

    As a new energy technology with distributed generation prospects, the load-following capability of solid oxide fuel cell (SOFC) systems is one of the main obstacles for commercial operation. This ...

    Model Selection Techniques.pdf

    have been proposed, following different philosophies and exhibiting varying performances. The purpose of this article is to bring a comprehensive overview of them, in terms of their motivation, ...

Global site tag (gtag.js) - Google Analytics