读书人

11.1 user micropost - a micropost m

发布时间: 2012-10-06 17:34:01 作者: rapoo

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:migraterake 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  endend
?

?

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  endend
?

?

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.userReturn the User object associated with the micropost.user.micropostsReturn 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 = :userend

?

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

?

?

读书人网 >操作系统

热点推荐