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

11.1 user micropost -- a micropost model.

 
阅读更多

1. we will first generate a micropost model.

 

$ rails generate model Micropost content:string user_id:integer

 note, if you the content is longer, you can use type "text" instead of string

 

2. next, since we expect to retrieve all microposts associated with a user, we need to add index on user_id and created_at columns.

 

add_index :microposts, [:user_id, :created_at]

 

also, note this line

 

      t.timestamps

will add two columns to the table, created_at and updated_at.

3. next, we need to do the migrate to the database, also do test:prepare to update the test database:
rake db:migrate
rake db:test:prepare

4. next, we will specify attr_accessible attrs.

we don't want user to edit the user_id attr through web, so we only add :content to attr_accessible

 

  attr_accessible :content
 

5. but this will create a difficulty for us, how to assign the user id when create a micropost?

go on with this question.

 

we will create user/micropost associations.

 

we start from test, TDD, yes.

 

describe Micropost do

  before(:each) do
    @user = Factory(:user)
    @attr = { :content => "value for content" }
  end

  it "should create a new instance given valid attributes" do
    @user.microposts.create!(@attr)
  end
  
  describe "user associations" do
    before(:each) do
      @micropost = @user.microposts.create!(@attr)
    end
    it "should have a user attribute" do
      @micropost.should respond_to(:user)
    end
    it "should have the right associated user" do
      @micropost.user_id.should == @user.id
      @micropost.user.should == @user
    end
  end
end
 

 

describe User do
  .
  .
  .
  describe "micropost associations" do

    before(:each) do
      @user = User.create(@attr)
    end

    it "should have a microposts attribute" do
      @user.should respond_to(:microposts)
    end
  end
end
 

 

6. all this test can pass after we add belongs_to and has_many methods to user.rb and micropost.rb.

 

after adding the two methods, we will have these methods for use:

 

micropost.user	Return the User object associated with the micropost.
user.microposts	Return an array of the user’s microposts.
user.microposts.create(arg)	Create a micropost (user_id = user.id).
user.microposts.create!(arg)	Create a micropost (exception on failure).
user.microposts.build(arg)	Return a new Micropost object (user_id = user.id).
 

note the last method, it will return a new object that is not saved yet, but the user_id is already assigned.

 

7.  to test the microposts that belong to a user, we need to factory some sample micropost records:

 

Factory.define :micropost do |micropost|
  micropost.content = "foo bar"
  micropost.association = :user
end

 

then in the test code, we can

@mp1 = Factory(:micropost, :user => @user, :created_at => 1.day.ago)
  @mp2 = Factory(:micropost, :user => @user, :created_at => 1.hour.ago)

 

you can see, factory not only allow us to mass assign to bypass attr_accessible,

it also allow us to assign created_at and updated_at.

 

for normal ActiveRecord, it won't alow us to do so, rails magic will assign the timestamp automatically.

 

here is the test code in user_spec.rb:

 

  describe "micropost associations" do
    before(:each) do
      @user = User.create(@attr)
      @mp1 = Factory(:micropost, :user => @user, :created_at => 1.day.ago)
      @mp2 = Factory(:micropost, :user => @user, :created_at => 1.hour.ago)
    end
    it "should have a microposts attribute" do
      @user.should respond_to :microposts
    end
    it "should have the right microposts in the right order" do
      @user.microposts.should == [@mp2, @mp1]
    end
  end
 

to make it pass, we need to order the microposts:

 

  default_scope :order => 'microposts.created_at DESC'

 this is the first time we encounter scope, we will get familiar later.

note, we use 

microposts.created_at

instead of

micropost.created_at

 

8. next, we will add test code to test that after destroying a user, the related micropost will be destroed automatically too.

 

    it "should destroy associated microposts" do
      @user.destroy
      [@mp1, @mp2].each do |micropost|
        Micropost.find_by_id(micropost.id).should be_nil
      end
    end

 notes:

 

 Micropost.find_by_id(micropost.id)

 will return nil if not found.

But

 

Micropost.find(micropost.id)

 will raise an exception 

 

lambda do 
  Micropost.find(micropost.id)
end.should raise_error(ActiveRecord::RecordNotFound)

 

9. the code to make the dependent destroy is very simple:

 

  has_many :microposts, :dependent => :destroy

 

10. micropost validations:

again, start from test:

 

  describe "validations" do
    it "should require a user id" do
      Micropost.new(@attr.should_not be_valid)
    end
    it "should require nonblank content" do
      @user.Microposts.build(:content => " ").should_not be_valid
    end
    it "reject long content" do
      @user.Microposts.build(:content => "a" * 141).should_not be_valid
    end
  end

 note, when contruct a new micropost object using associated user, we use

build()

instead of

Micropost.new

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics