7.3 better user views

Chapter 7.3

 

now, we have a good user model, we can try to make a show page to show the user info.

 

we already have some test for the new action in the users controller.

 

now we will add some test for the show action in this controller.

 

But at once, we facing a challenge, the test of show action will need to the use of an instance of the User model. We will overcome it using the technique of

 

"factories"

 

(many experienced Rails programmers find factory is much more flexible and easir to maintain then fixtures, which Rails uses by default)

 

we will use the factories generated by Factory Girl, a ruby gem.

so we need to add this gem to gem file,

(since it is only used in test, so need to include it into the :test group)

 

group :test do

gem 'factory_girl_rails', '1.0'

end

 

then run 

 

bundle install

 

next, we are ready to create the file 

spec/factories.rb

in this file, it will define a User factory, since this file is under spec dir, so Rspec will load our factories auto whenever test run.

 

Factory.define :user do |user|

user.name "abcd efg"

user.email  "[email protected]"

user.password "secret"

user.password_confirmation "secret"

end

 

then in the test, we can create a User factory like this:

@user = Factory(:user)

 

this line should be in before(:each) block in the spec test file.

 

 

2. in functional test, there are four hashs that are ready to use after finishing a browser request:


Assigns - Any objects that are stored as instance variables in actions for use in views.

cookies

flash

session


and, you also have access to 3 instance variables in your functional test:

@controller

@request

@response

 

 

3. the users_controller_spec.rb

 

 

require 'spec_helper'

describe UsersController do
  render_views

  describe "GET 'show'" do

    before(:each) do
      @user = Factory(:user)
    end

    it "should be successful" do
      get :show, :id => @user
      response.should be_success
    end

    it "should find the right user" do
      get :show, :id => @user
      assigns(:user).should == @user
    end
  end
  .
  .
  .
end
 

now, you see the use of

 

assigns(:user)

 

will return the value of the instance variable @user.

 

you may note I use 

 

get :show

 

instead of 

 

get 'show'

 

because former is more REST!!

 

you may also note I use

 

:id => @user

 

instead of 

 

:id => @user.id

 

because rails will do the job of converting @user to @user.id, and it is very very common rails way to just use :id => @user

 

 

3. ok, we done the test, now we will do the views.

 

let's start from test again:

 

 

it "should have the right title" do
	get :show, :id => @user
	response.should have_selector("title", :content => @user.name)
end
it "should include the user name" do
	get :show, :id => @user
	response.should have_selector("h1", :content => @user.name)
end
it "should have a profile image" do
	get :show, :id => @user
	response.should have_selector("h1>img", :class => "gravatar")
end

 

note: 

have_selector is a helper method from rspec to test the content inside a html tag.


and it can also test the CSS class of the element.

 

(the helper method define in application_helper.rb can only be seen by the views!!!)

 

some malicious user will enter name with script, which would be inject into our application by the title helper, before rails 3, we use h() to escape, (short for html_escape), but in Rails 3, all embedded Ruby text is escaped by default.

 

so <script> will be embedded as 

&lt;script&gt;

 

(but if you want to not escape, you can use (raw) method.)

 

 

(if your app need to handle images or other file uploads, Paperclip gem is the way to go)

 

 

4. to deal with img, we will use Gravatar gem.

 

gem 'gravatar_image_tag', '1.0.0.pre2'

 

bundle install

 

<%= gravatar_image_tag '[email protected]' %>

 

user = User.first

user.update_attributes(:email => "[email protected]", :password => "fo", :password_confirmation => "fo")

 

we still need to add a :class attr to the img element, 

 

<%= gravatar_image_tag @user.email, :class => "gravatar" %>

 

but we will use this logo in many places, if we use :class everywhere, it is a dup, so we will extract it into helper.

 

since this image is in general associated with a user, so we put it into user_helper.rb

(actually, all helper method are viewable in all views, put it to which helper file is just to be more clear for you, doesn't matter at all)

 

we define a helper method for view to use:

 

module UserHelper

def gravatar_for(user, options => {:size => 50})

gravatar_image_tag(user.email.downcase, :alt => user.name, :class => 'gravatar', :gravatar => options)

end

end

 

 

5. a user sidebar:

 

<%= link_to user_path(@user), @user%>

 

you may find why it use @user instead of user_path(@user)

 

this is also a rails convention, it is the same to 

 

<%= link_to user_path(@user), user_path(@user)%>

 

but rails like using the former way!!!

 

 

你可能感兴趣的:(view)