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

10.1 updating users.

 
阅读更多

1. git checkout -b updating-users

 

2. in this chapter, we will make you can update user profile.

a. we will use a "edit" action to render a view to edit user.

b. we will use "update" action and a "PUT" request to update user profile

c. we need to make sure only current user can update their information. this need a "before_filter"

 

3. edit form, we will start from TDD again!!

 

describe UserController do
	describe "get 'edit'" do
		before(:each) do
			@user = Factory(:user)
			test_sign_in(@user)
		end

		it "should be success" do
			get :edit, :id => @user
			response.should be_success
		end
		it "should have the right title" do
			get :edit, :id => @user
			response.should have_selector("title", :content => "Edit user")
		end
		it "should have the link to gravatar" do
			get :edit, :id => @user
			gravatar_url = "http://gravatar.com/emails"
			response.should have_selector("a", :href => gravatar_url, :content => "change")
		end
	end
end

 4. now it is time to write the view code:

 

<h1>Edit User</h1>

<%= form_for @user do |f| %>
	<%= render "shared/error_messages", :object => f.object %>
	<div class="field">
		<%= f.label :name %>								<br />
		<%= f.text_field :name %>							<br />
		<%= f.label :email %>								<br />
		<%= f.text_field :email %>							<br />
		<%= f.label :password %>							<br />
		<%= f.password_field :password %>					<br />
		<%= f.label :password_confirmation, "Confirmation" %><br />
		<%= f.password_field :password_confirmation %>		<br />
	</div>
	<div class="action">
		<%= f.submit "Update"%>
	</div>
<% end %>

<div>
	<%= gravatar_for @user %>
	<a href="http://gravatar.com/emails">Change</a>
</div>

you can find we passed a object param when rendering partial .

this is common because a real partial should not rely on the fact that there is a @user object.

this is especially useful when composing a form, 

<%= render 'shared/error_messages', :object => f.object %>

 

 this create a var called object in the partial, 

 

now we need to re-write the _error_messages partial:

 

<% if object.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(object.errors.count, "error") %> 
        prohibited this <%= object.class.to_s.underscore.humanize.downcase %> 
        from being saved:</h2>
    <p>There were problems with the following fields:</p>
    <ul>
    <% object.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

 we can learn two helper method here:

 

"ActiveRecord".underscore ======> active_record  (lower case and add _ )


"active_record".humanize =======> Active record  (capitalize, and replace _ with space.)

 

5. next, let's look at the html gened by the form:

 

 

<form action="/users/1" class="edit_user" id="edit_user_1" method="post">
  <input name="_method" type="hidden" value="put" />
  . . . </form>

 

note this hidden line:

 

since web browser can't natively send "PUT" request, rails fake it with a post request, and a hidden input field.

 

6. there is another magic that you may wondering,

 

we use the same code for edit form and new form, but why the html generated are different?

for new action, rails use a post method, and for edit action, rails use a put method.

 

the answer is simple and trikey, rails will run

 

@user.new_record?

 

to judge if this record is a new one, or already exist in database.

 

so rails will know to use a put request or post request, clever?? cool!

 

7. next is the test for update success and update failure.

  describe "PUT 'update'" do
    before(:each) do
      @user = Factory(:user)
      test_sign_in(@user)
    end
    describe "update failure" do
      before(:each) do
        @attr = {:name => "", :email => "", :password => "", :password_confirmation => "" }
      end
      it "should render the edit page" do
        put :update, :id => @user, :user => @attr
        response.should render_template('edit')
      end
      it "should have the right title" do
        put :update, :id => @user, :user => @attr
        response.should have_selector("title", :content => "Edit user")
      end
    end

    describe "update success" do
      before(:each) do
        @attr = { :name => "New Name", :email => "user@example.org",
                          :password => "barbaz", :password_confirmation => "barbaz" }
      end
      it "should redirect to user show page" do
        put :update, :id => @user, :user => @attr
        response.should redirect_to user_path(@user)
      end
      it "should change user's attrs" do
        put :update, :id => @user, :user => @attr
        @user.reload
        @user.name.should == @attr[:name]
        @user.email.should == @attr[:email]
      end
      it "should have a flash message" do
        put :update, :id => @user, :user => @attr
        flash[:success].should =~ /updated/i
      end
    end
  end

 one thing to note:

 

@user.reload  ========> this will reload the @user content from database.

 

8. next, we will implement the update method in the controller:

 

  def update
    @user = User.find_by_id(params[:id])
    if @user.update_attributes(params[:user])
      flash[:success] = "Profile updated"
      redirect_to @user
    else
      @title = "Edit user"
      render 'edit'
    end
  end
 
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics