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

11.3 manipulating microposts.

 
阅读更多

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
 

 

分享到:
评论

相关推荐

    matlab homework1

    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 ...

    C library for encoding, decoding and manipulating JSON data.zip

    JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,被广泛用于Web服务和应用程序之间的数据传输。在C语言环境中,处理JSON数据通常需要借助专门的库,本压缩包提供的就是一个C语言编写的用于编码、...

    Learning Apache Flink电子版

    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 ...

    Springer.The.Developer’s.Guide.to.Debugging.2008.pdf

    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 ....

    Debugging with GDB --2003年6.0

    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 ....

    Debugging with GDB --2001年5.3

    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 ....

    ARDUINO library库函数

    这是标准的官方库,请大家仔细参详! Libraries 目录 Libraries provide extra ... working with hardware or manipulating data. To use a library in a sketch, select it from Sketch &gt; Import Library.

    深入理解计算机系统(英文版)

    2 Representing and Manipulating Information 21 2.1 Information Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2.1.1 HexadecimalNotation . . . . . . . . . . . ...

    Conditional Branch Logger v1.0 by Blabberer / dELTA / Kayaker

    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.

    SystemVerilog Reference Manual 3.1a(中英文版)+最新SV IEEE 标准

    Table of Contents Section 1 Introduction to SystemVerilog ...................................................................................................... 1 Section 2 Literal Values................

    spring-framework-reference4.1.4

    Not Using Commons Logging ................................................................... 12 Using SLF4J ..............................................................................................

    Android代码-一个基本的示例Android应用程序,以非常简单的方式理解MVP。

    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-using-Pulse-Coupled-Neural-Networks-Applications-in-Python

    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 ...

    Android代码-android-mvvm-sample-app

    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 ...

    spring-framework-reference-4.1.2

    Not Using Commons Logging ................................................................... 12 Using SLF4J ..............................................................................................

    Practical Apache Struts2 Web 2.0 Projects

    Enable participation by manipulating data. Share data by implementing powerful search utilities. Syndicate web content created using RSS and REST. Discover advanced features available...

    SAS Programming II Manipulating Data with the DATA Step.rar

    《SAS编程II:使用DATA步操作数据》是SAS学习者进阶的重要教程,主要聚焦于如何利用SAS的DATA步来高效处理和转换数据。在这个教程中,你将深入理解SAS编程的核心概念,特别是DATA步在数据管理中的应用。...

    Prentice.Hall.C++.for.Business.Programming.2nd.Edition.2005.chm

    Section 11.3. Constructor Overloading and Destructors 496 Section 11.4. Default Arguments and Object Assignment 504 Section 11.5. General Function Overloading and Function Templates 511 Chapter...

Global site tag (gtag.js) - Google Analytics