1. since all micropost actions will be done in users page, so we only need :create and :destroy actions.
so the routes will be:
resources :microposts, :only => [:create, :destroy]
2. we will test access control to the microposts controller first:
describe MicropostsController do render_views describe "access control" do it "should deny access to 'create'" do post :create response.should redirect_to(signin_path) end it "should deny access to 'destroy'" do delete :destroy, :id => 1 response.should redirect_to(signin_path) end end end
3. next we will try to create mircropost.
here is the test:
describe MicropostsController do . . . describe "POST 'create'" do before(:each) do @user = test_sign_in(Factory(:user)) end describe "failure" do before(:each) do @attr = { :content => "" } end it "should not create a micropost" do lambda do post :create, :micropost => @attr end.should_not change(Micropost, :count) end it "should render the home page" do post :create, :micropost => @attr response.should render_template('pages/home') end end describe "success" do before(:each) do @attr = { :content => "Lorem ipsum" } end it "should create a micropost" do lambda do post :create, :micropost => @attr end.should change(Micropost, :count).by(1) end it "should redirect to the home page" do post :create, :micropost => @attr response.should redirect_to(root_path) end it "should have a flash message" do post :create, :micropost => @attr flash[:success].should =~ /micropost created/i end end end end
then we will write the create action.
def create @micropost = current_user.microposts.build(params[:micropost]) if @micropost.save flash[:success] = "Micropost created!" redirect_to root_path else render 'pages/home' end end
4. now it is time to make a form for creating new micropost:
<% if signed_in? %> <table class="front" summary="For signed-in users"> <tr> <td class="main"> <h1 class="micropost">What's up?</h1> <%= render 'shared/micropost_form' %> </td> <td class="sidebar round"> <%= render 'shared/user_info' %> </td> </tr> </table> <% else %> <h1>Sample App</h1> <p> This is the home page for the <a href="http://railstutorial.org/">Ruby on Rails Tutorial</a> sample application. </p> <%= link_to "Sign up now!", signup_path, :class => "signup_button round" %> <% end %>
and the partials:
<%= form_for @micropost do |f| %> <%= render 'shared/error_messages', :object => f.object %> <div class="field"> <%= f.text_area :content %> </div> <div class="actions"> <%= f.submit "Submit" %> </div> <% end %>
<div class="user_info">
<a href="<%= user_path(current_user) %>"> <%= gravatar_for current_user, :size => 30 %> <span class="user_name"> <%= current_user.name %> </span> <span class="microposts"> <%= pluralize(current_user.microposts.count, "micropost") %> </span> </a> </div>
5. add a feed of this user's micropost:
this feed include all this user's micropost as an array:
here is the test codes:
describe "status feed" do it "should have a feed" do @user.should respond_to :feed end it "should include the user's microposts" do @user.feed.include?(@mp1).should be_true @user.feed.include?(@mp2).should be_true end it "should not include a diff user's micropost" do mp3 = Factory(:micropost, :user => Factory(:user, :email => Factory.next(:email))) @user.feed.include?(mp3).shoud be_false end
6. for the feed method:
def feed Mircropost.where("user_id = ?", id) end
note:
the question mark is use to escape the id to prevent SQL injection.
7. in the home controller we need to prepare the pagination of the feed:
def home @title = "Home" if signed_in? @micropost = Micropost.new @feed_items = current_user.feed.paginate(:page => params[:page]) end end
8. then it is turn for the _feed partial:
<% unless @feed_items.empty? %> <table class="microposts" summary="User microposts"> <%= render :partial => 'shared/feed_item', :collection => @feed_items %> </table> <%= will_paginate @feed_items %> <% end %>
you can see that we are not omitting the :partial param in this rendering of partial.
because we have another param of :collection, so the :partial can not be omitted.
9. now it is the _feed_item.html.erb partial:
<tr> <td class="gravatar"> <%= link_to gravatar_for(feed_item.user), feed_item.user %> </td> <td class="micropost"> <span class="user"> <%= link_to feed_item.user.name, feed_item.user %> </span> <span class="content"><%= feed_item.content %></span> <span class="timestamp"> Posted <%= time_ago_in_words(feed_item.created_at) %> ago. </span> </td> <% if current_user?(feed_item.user) %> <td> <%= link_to "delete", feed_item, :method => :delete, :confirm => "You sure?", :title => feed_item.content %> </td> <% end %> </tr>
10. destroying micropost:
we need to add delete link to _mircropost.html.erb partial:
<% if current_user?(micropost.user) %> <td> <%= link_to 'Delete', micropost, :method => :delete, :confirm => "you sure?", :title => micropost.content %> </td> <% end %>
look at the below code, it is amazing:
user = micropost.user rescue User.find(micropost.user_id)
in this line of code, it try to get micropost.user, if get an exception, it will instead get from User.find(micropost.user_id)
11. then let's try to add test to the destroy action:
describe MicropostsController do . . . describe "DELETE 'destroy'" do describe "for an unauthorized user" do before(:each) do @user = Factory(:user) wrong_user = Factory(:user, :email => Factory.next(:email)) test_sign_in(wrong_user) @micropost = Factory(:micropost, :user => @user) end it "should deny access" do delete :destroy, :id => @micropost response.should redirect_to(root_path) end end describe "for an authorized user" do before(:each) do @user = test_sign_in(Factory(:user)) @micropost = Factory(:micropost, :user => @user) end it "should destroy the micropost" do lambda do delete :destroy, :id => @micropost end.should change(Micropost, :count).by(-1) end end end end
12. let's try to implement the destroy action:
before_filter :authorized_user, :only => :destroy
class MicropostsController < ApplicationController
before_filter :authenticate, :only => [:create, :destroy] before_filter :authorized_user, :only => :destroy . . . def destroy @micropost.destroy redirect_back_or root_path end private def authorized_user @micropost = current_user.microposts.find_by_id(params[:id]) redirect_to root_path if @micropost.nil? end end
note, we use find_by_id instead of find, the later one will throw an exception if not found.
if you are comfortable with the exception, you can also write this code:
def authorized_user @micropost = current_user.microposts.find(params[:id]) rescue redirect_to root_path end
13. ok, we are done, now we will do some integration test for micropost.
describe "Microposts" do before(:each) do user = Factory(:user) visit signin_path fill_in :email, :with => user.email fill_in :password, :with => user.password click_button end describe "creation" do describe "failure" do it "should not make a new micropost" do lambda do visit root_path fill_in :micropost_content, :with => "" click_button response.should render_template('pages/home') response.should have_selector("div#error_explanation") end.should_not change(Micropost, :count) end end describe "success" do it "should make a new micropost" do content = "Lorem ipsum dolor sit amet" lambda do visit root_path fill_in :micropost_content, :with => content click_button response.should have_selector("span.content", :content => content) end.should change(Micropost, :count).by(1) end end end end
发表评论
-
12.3.3 scaling issue of the status feed
2011-10-30 17:54 738the problem of the implementati ... -
12.3 the status feed
2011-10-30 15:34 8051. we need to get all the micro ... -
12.2 a working follow button with Ajax
2011-10-29 18:10 8771. in the last chapter, in the ... -
12.2 a web interface for following and followers.
2011-10-28 22:14 8351.before we do the UI, we need ... -
12. following user, 12.1 relationship model
2011-10-18 14:29 7021. we need to use a relationshi ... -
11.2 show microposts.
2011-10-17 12:01 6481. add test to test the new use ... -
11.1 user micropost -- a micropost model.
2011-10-17 10:43 10631. we will first generate a mic ... -
10.4 destroying users.
2011-10-16 15:47 689in this chapter, we will add de ... -
10.3 showing users list
2011-10-15 20:41 731in this chapter, we will do use ... -
10.2 protect pages.
2011-10-15 15:11 603again, we will start from TD ... -
10.1 updating users.
2011-10-14 18:30 6621. git checkout -b updating-use ... -
9.4 sign out
2011-10-13 15:21 682whew!!!, last chapter is a long ... -
9.3 sign in success.
2011-10-12 15:39 6811. we will first finish the cre ... -
9.1 about flash.now[:error] vs flash[:error]
2011-10-12 15:37 670There’s a subtle difference ... -
9.2 sign in failure
2011-10-12 12:19 605start from TDD!!! 1. requir ... -
9.1 sessions
2011-10-12 10:00 612a session is a semi-permanent c ... -
what test framework should you use?
2011-10-11 16:56 0for integration test, i have no ... -
what test framework should you use?
2011-10-11 16:56 0<p>for integration test, ... -
8.4 rspec integration tests
2011-10-11 16:53 675in integration test, you can te ... -
8.3 sign up success
2011-10-11 14:39 732Chapter 8.3 this part, we will ...
相关推荐
matlab作业1题目 Introduction to MATLAB This homework is designed to teach you to think in terms of matrices and vectors because this is how MATLAB organizes data. You will find that complicated ...
Chapter 5: Manipulating Text . . . . . . . . . .71 Chapter 6: Playing with Multimedia . . . . . . . 89 Chapter 7: Administering File Systems . . . . . . 103 Chapter 8: Backups and Removable Media . . ...
C library for encoding, decoding and manipulating JSON data
Bringing the power of SQL to Flink, this book will then explore the Table API for querying and manipulating data. In the latter half of the book, readers will get to learn the remaining ecosystem of ...
1. Building ASP.NET Pages ASP.NET and the .NET ... For example, for each language, you would have to include methods for accessing the file system, working with databases, and manipulating strings.
1 You Write Software; You have Bugs . . . . . . . . ....2 A Systematic Approach to Debugging .... ....2.2 Making the Most of Your Opportunities ....2.3 13 Golden Rules ....2.3.1 Understand the Requirements ....
Table of Contents Summary of gdb . . . . . . . . ....Free software ....Free Software Needs Free Documentation ....Contributors to gdb....1 A Sample gdb Session ....2 Getting In and Out of gdb ....2.1 Invoking gdb ....
Table of Contents Summary of GDB . . . . . . . . ....Free software ....Free Software Needs Free Documentation ....Contributors to GDB ....1 A Sample GDB Session ....2 Getting In and Out of GDB ....Invoking GDB ....
这是标准的官方库,请大家仔细参详! Libraries 目录 Libraries provide extra ... working with hardware or manipulating data. To use a library in a sketch, select it from Sketch > Import Library.
2 Representing and Manipulating Information 21 2.1 Information Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2.1.1 HexadecimalNotation . . . . . . . . . . . ...
SAS Programming II Manipulating Data with the DATA Step.rar
Advanced Bash-Scripting Guide 高级Bash脚本编程指南>> 一本深入学习shell脚本艺术的书籍 非常好的书 强烈推荐 附有超多实例 Advanced Bash-Scripting Guide.......................................................
Conditional Branch Logger is a plugin which gives control and logging capabilities for conditional ... Numerous options are available for fine tuning the logging ranges and manipulating breakpoints.
Table of Contents Section 1 Introduction to SystemVerilog ...................................................................................................... 1 Section 2 Literal Values................
Not Using Commons Logging ................................................................... 12 Using SLF4J ..............................................................................................
data: It contains all the data accessing and manipulating components. ui: View classes along with their corresponding Presenters. utils: Utility classes. Key points Using base abstract classes to ...
Image processing algorithms based on the mammalian visual cortex are powerful tools for extraction information and manipulating images. This book reviews the neural theory and translates them into ...
data: It contains all the data accessing and manipulating components. ui: View classes along with their corresponding ViewModel. utils: Utility classes. Using Jetpack Architecture Components ...
截至 2011-08-29 官方公布的最新 hibernate 文档,此为英文版,配套中文版下载地址:http://download.csdn.net/source/3557584。 详细信息: 版本:3.6.3.Final,作者:Gavin King, Christian Bauer, Max Rydahl ...
Not Using Commons Logging ................................................................... 12 Using SLF4J ..............................................................................................