Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
ruby-on-rails-exploration-part-1

Introduction

This is an overview of things I've learnt while working on my side project anonforum in Ruby on Rails.

Today's topics:

  • Testing (models and controllers)
  • Routing
  • Controllers
  • Views (helpers)

Testing! Getting Started

This is everyone's favourite part of development right?!?! Thankfully testing in Rails is very straight forward.

To run tests you simply run:

rails test {file/directory}

Testing: Simple Route Test

I started with a basic test to determine if the index route returned successfully. To do this I started by generating a controller and test:

rails g controller post --no-assets --no-helper
create  app/controllers/post_controller.rb
      invoke  erb
      create    app/views/post
      invoke  test_unit
      create    test/controllers/post_controller_test.rb

test/controllers/post_controller_test.rb

require 'test_helper'
class PostControllerTest < ActionDispatch::IntegrationTest
  test "can see threads" do
    get '/'
    assert_response :success
  end
end

Which failed because the route and controller was not setup, so I updated my routes and controller files then added an index view file app/views/post/index.html.erb.

config/routes.rb

Rails.application.routes.draw do
  get '/' => 'post#index'
end

app/controllers/post_controller.rb

class PostController < ApplicationController
  def index
    render 'index'
  end
end

Now we run the test:

rails test test/controllers/post_controller_test.rb
Run options: --seed 59367

# Running:

.

Finished in 0.795857s, 1.2565 runs/s, 1.2565 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

Green!

Now let's make sure posts are being passed to the view.

test/controllers/post_controller_test.rb

require 'test_helper'
class PostControllerTest < ActionDispatch::IntegrationTest
  test "can see threads" do
    get '/'
    assert_response :success
    assert_not_nil assigns(:posts)
  end
end

This will fail as all we're currently doing is rendering the view, so let's make all the post avaiable to the view

app/controllers/post_controller.rb

class PostController < ApplicationController
  def index
    @posts = Post.all
    render 'index'
  end
end

And let's add some content to our index view:

app/views/post/index.html.erb

<ul>
  <% @posts.each do |post| %>
    <li>
      <h5><a href="#"><%= post.title %></a></h5>
      <p><%= post.body %></p>
    </li>
  <% end %>
</ul>

Re-run the test:

rails test test/controllers/post_controller_test.rb
Run options: --seed 10337

# Running:

.

Finished in 0.756118s, 1.3225 runs/s, 2.6451 assertions/s.
1 runs, 2 assertions, 0 failures, 0 errors, 0 skips

Green again!

Now we'd like to be able to create new posts (threads), so let's add a test for seeing the new post (thread) form

test/controllers/post_controller_test.rb

require 'test_helper'
class PostControllerTest < ActionDispatch::IntegrationTest
  test "can see threads" do
    get '/'
    assert_response :success
    assert_not_nil assigns(:posts)
  end

  test "can see new thread form" do
    get '/thread/new'
    assert_response :success
  end
end

This fails as we have yet to define a route for it and a controller method for it and there is no view file, so let's update those now

config/routes.rb

Rails.application.routes.draw do
  get '/' => 'post#index'
  get '/thread/new' => 'post#new'
end

app/controllers/post_controller.rb

class PostController < ApplicationController
  def index
    render 'index'
  end
  def new
    render 'new'
  end
end

Create app/views/post/new.html.erb and add the following

<%= form_tag("/thread") do %>
  <input name="title" type="text" />
  <textarea name="body"></textarea>
  <button type="submit">Submit</button>
<% end %>

I'm sure you noticed the method above form_tag("/thread") do, this generates some content for us we don't want to be bothered with like CSRF tokens, encoding/charset, route action, and http method. Just ignore the /thread part for now we'll adding that in later. The output of the above will look like:

<form action="/thread" accept-charset="UTF-8" method="post">
  <input name="utf8" type="hidden" value="&#x2713;">
  <input type="hidden" name="authenticity_token" value="Z3Gor/8T/h0WkynAH/IufRxRlvEBpUc4QN0dIEbnGDQjCCPBLCOI2qXgKyGXQAnGujj14zSeZBiJsi+PaP9jGA==">
  <input id="title" name="title" type="text">
  <textarea id="body" name="body"></textarea>
  <button type="submit">Submit</button>
</form>

Re-run the test:

rails test test/controllers/post_controller_test.rb
Run options: --seed 58678

# Running:

..

Finished in 0.761473s, 2.6265 runs/s, 3.9397 assertions/s.
2 runs, 3 assertions, 0 failures, 0 errors, 0 skips

Green again!

Now that the form is setup we need to make sure the route that creates post (threads) works, here's the setup for the test

test/controllers/post_controller_test.rb

require 'test_helper'
class PostControllerTest < ActionDispatch::IntegrationTest
  test "can see threads" do
    get '/'
    assert_response :success
    assert_not_nil assigns(:posts)
  end

  test "can see new thread form" do
    get '/thread/new'
    assert_response :success
  end

  test "can create a thread" do
    get "/thread/new"
    assert_response :success
    post "/thread",
      params: { title: "My New Thread", body: "The body of my new thread" }
    assert_response :redirect
    follow_redirect!
    assert_response :success
    assert_select "a", "My New Thread"
  end
end

This test is a little more involved so we'll take it line by line:

  • test "can create a thread" do

    • naming the test
  • get "/thread/new"

    • go to the new thread (post) form page
  • post "/thread", params: { title: "My New Thread", body: "The body of my new thread" }

    • Do a POST action against the route /thread with the parameters { title: "My New Thread", body: "The body of my new thread" }
  • assert_response :redirect

    • Assert the response is a redirect (302)
  • follow_redirect!

    • Follow the redirect to make new assertions on the redirected page (which will be / in our case)
  • assert_response :success

    • Assert the page redirected to gives us a successful response (200)
  • assert_select "a", "My New Thread"

    • Assert an element on the page of a (anchor tag) has the content My New Thread

All this just to check if a post (thread) was created successfully!

Now we know this will fail as we've setup none of the above, so let's update all the necessary files now

config/routes.rb

Rails.application.routes.draw do
  get '/' => 'post#index'
  get '/thread/new' => 'post#new'
  post '/thread' => 'post#create'
end

app/controllers/post_controller.rb

class PostController < ApplicationController
  def index
    render 'index'
  end
  def new
    render 'new'
  end

  def create
    @post = Post.new(title: params[:title], body: params[:body])
    if @post.save
      redirect_to action: 'index' and return
    else
      render 'new'
    end
  end
end

Now let's try the tests again:

rails test test/controllers/post_controller_test.rb
Run options: --seed 42830

# Running:

...

Finished in 0.775124s, 3.8703 runs/s, 9.0308 assertions/s.
3 runs, 7 assertions, 0 failures, 0 errors, 0 skips

Conclusion

There you have it! I can now create threads (posts) in my application! I ran into a few bumps while trying to figure this out, the documentation isn't very straight forward to navigate but once I found what I was looking for it worked almost flawlessly. Also, there's a few things that were left out like validation error output and the styling of the mark up. If you'd like to see more have a look here https://github.com/patoui/anon-forum.

Feel free to share! Thanks!

Gist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.