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
<script>
(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!!!