Search code examples
rubyruby-on-rails-4rspecrspec-railsrailstutorial.org

Hartl's Rails Tutorial (rails-4-0) section 10.3.2 param not found


I've been struggling with this for a while now and can't figure out what is happening. I'm working my way through Michael Hartl's Rails tutorial and have come to have an issue with some of my tests. These are the failing test results:

Failures:

  1) User pages signup with invalid information should not create a user
     Failure/Error: expect { click_button submit }.not_to change(User, :count)
     ActionController::ParameterMissing:
       param not found: user
     # ./app/controllers/users_controller.rb:61:in `user_params'
     # ./app/controllers/users_controller.rb:21:in `create'
     # ./spec/requests/user_pages_spec.rb:89:in `block (5 levels) in <top (required)>'
     # ./spec/requests/user_pages_spec.rb:89:in `block (4 levels) in <top (required)>'

  2) User pages signup with invalid information after submission 
     Failure/Error: before { click_button submit }
     ActionController::ParameterMissing:
       param not found: user
     # ./app/controllers/users_controller.rb:61:in `user_params'
     # ./app/controllers/users_controller.rb:21:in `create'
     # ./spec/requests/user_pages_spec.rb:93:in `block (5 levels) in <top (required)>'

  3) User pages signup with invalid information after submission 
     Failure/Error: before { click_button submit }
     ActionController::ParameterMissing:
       param not found: user
     # ./app/controllers/users_controller.rb:61:in `user_params'
     # ./app/controllers/users_controller.rb:21:in `create'
     # ./spec/requests/user_pages_spec.rb:93:in `block (5 levels) in <top (required)>'

  4) User pages signup with valid information should create a user
     Failure/Error: before { valid_signup(user) }
     Capybara::ElementNotFound:
       Unable to find field "Name"
     # ./spec/support/utilities.rb:10:in `valid_signup'
     # ./spec/requests/user_pages_spec.rb:102:in `block (4 levels) in <top (required)>'

  5) User pages signup with valid information after saving the user 
     Failure/Error: before { valid_signup(user) }
     Capybara::ElementNotFound:
       Unable to find field "Name"
     # ./spec/support/utilities.rb:10:in `valid_signup'
     # ./spec/requests/user_pages_spec.rb:102:in `block (4 levels) in <top (required)>'

  6) User pages signup with valid information after saving the user 
     Failure/Error: before { valid_signup(user) }
     Capybara::ElementNotFound:
       Unable to find field "Name"
     # ./spec/support/utilities.rb:10:in `valid_signup'
     # ./spec/requests/user_pages_spec.rb:102:in `block (4 levels) in <top (required)>'

  7) User pages signup with valid information after saving the user 
     Failure/Error: before { valid_signup(user) }
     Capybara::ElementNotFound:
       Unable to find field "Name"
     # ./spec/support/utilities.rb:10:in `valid_signup'
     # ./spec/requests/user_pages_spec.rb:102:in `block (4 levels) in <top (required)>'

Finished in 9.1 seconds
119 examples, 7 failures

Failed examples:

rspec ./spec/requests/user_pages_spec.rb:88 # User pages signup with invalid information should not create a user
rspec ./spec/requests/user_pages_spec.rb:95 # User pages signup with invalid information after submission 
rspec ./spec/requests/user_pages_spec.rb:96 # User pages signup with invalid information after submission 
rspec ./spec/requests/user_pages_spec.rb:104 # User pages signup with valid information should create a user
rspec ./spec/requests/user_pages_spec.rb:113 # User pages signup with valid information after saving the user 
rspec ./spec/requests/user_pages_spec.rb:115 # User pages signup with valid information after saving the user 
rspec ./spec/requests/user_pages_spec.rb:116 # User pages signup with valid information after saving the user 

So Here's my user_pages_spec.rb:

require 'spec_helper'

describe "User pages" do

  subject { page }

  describe "index" do

    let(:user) { FactoryGirl.create(:user) }

    before do
      sign_in user
      visit users_path
    end

    it { should have_title('All users') }
    it { should have_content('All users') }

    describe "pagination" do

      before(:all) { 30.times { FactoryGirl.create(:user) } }
      after(:all) { User.delete_all }

      it { should have_selector('div.pagination') }

      it "should list each user" do
        #User.all.each do |user|
        User.paginate(page: 1).each do |user|
          expect(page).to have_selector('li', text: user.name)
        end
      end
    end

    describe "delete links" do

      it { should_not have_link('delete') }

      describe "as an admin user" do
        let(:admin) { FactoryGirl.create(:admin) }
        before do
          sign_in admin
          visit users_path
        end

        it { should have_link('delete', href: user_path(User.first)) }
        it "should be able to delete another user" do
          expect do
            click_link('delete', match: :first)
          end.to change(User, :count).by(-1)
        end
        it { should_not have_link('delete', href: user_path(admin)) }

      end
    end
  end

  describe "profile page" do
    let(:user) { FactoryGirl.create(:user) }
    let!(:m1) { FactoryGirl.create(:micropost, user: user, content: "Foo") }
    let!(:m2) { FactoryGirl.create(:micropost, user: user, content: "Bar") }

    before { visit user_path(user) }

    it { should have_content(user.name) }
    it { should have_title(user.name) }

    describe "microposts" do
      it { should have_content(m1.content) }
      it { should have_content(m2.content) }
      it { should have_content(user.microposts.count) }
    end
  end

  describe "signup page" do
    before { visit signup_path }

    it { should have_content('Sign up') }
    it { should have_title(full_title('Sign up')) }
  end

  describe "signup" do

    before { visit signup_path }

    let(:submit) { "Create my account" }

    describe "with invalid information" do
      it "should not create a user" do
        expect { click_button submit }.not_to change(User, :count)
      end

      describe "after submission" do
        before { click_button submit }

        it { should have_title('Sign up') }
        it { should have_content('error') }
      end
    end

    describe "with valid information" do
      let(:user) {FactoryGirl.build(:user)}
      before { valid_signup(user) }

      it "should create a user" do
        expect { click_button submit }.to change(User, :count).by(1)
      end

      describe "after saving the user" do
        before { click_button submit }

        #let(:user) { User.find_by(email: '[email protected]') }

        it { should have_title(user.name) }
        #it { should have_selector('title', text: user.name) }
        it { should have_selector('div.alert.alert-success', text: 'Welcome') }
        it { should have_link('Sign out') }
      end
    end
  end

  describe "edit" do
    let(:user) { FactoryGirl.create(:user) }
    before do
      sign_in user
      visit edit_user_path(user)
    end

    describe "page" do
      it { should have_content("Update your profile") }
      it { should have_title("Edit user") }
      it { should have_link('Change', href: 'http://gravatar.com/emails') }
    end

    describe "with invalid information" do
      before { click_button "Save changes" }

      it { should have_content('error') }
    end

    describe "with valid information" do
      let(:new_name) { "New Name" }
      let(:new_email) { "[email protected]" }
      before do
        fill_in "Name", with: new_name
        fill_in "Email", with: new_email
        fill_in "Password", with: user.password
        fill_in "Confirm Password", with: user.password
        click_button "Save changes"
      end

      it { should have_title(new_name) }
      it { should have_selector('div.alert.alert-success') }
      it { should have_link('Sign out', href: signout_path) }
      specify { expect(user.reload.name).to eq new_name }
      specify { expect(user.reload.email).to eq new_email }
    end

    describe "forbidden attributes" do
      let(:params) do
        { user: {admin: true, password: user.password, password_confirmation: user.password } }
      end
      before do
        sign_in user, no_capybara: true
        patch user_path(user), params
      end
      specify { expect(user.reload).not_to be_admin }
    end
  end
end

users_controller.rb:

class UsersController < ApplicationController
  before_action :signed_in_user, only: [:index, :edit, :update, :destroy]
  before_action :correct_user, only: [:edit, :update]
  before_action :admin_user, only: :destroy
  before_filter :signed_in_user_filter, only: [:new, :create]

 def index
    @users = User.paginate(page: params[:page])
  end

  def show
   @user = User.find(params[:id])
    @microposts = @user.microposts.paginate(page: params[:page])
 end

  def new
   @user = User.new
  end

  def create
   @user = User.new(user_params)
   if @user.save
      sign_in @user
      flash[:success] = "Welcome to the Sample App!"
     redirect_to @user
   else
     render 'new'
   end
  end

  def destroy
    @user = User.find(params[:id])
    if current_user == @user
      flash[:error] = "You must not delete yourself."
      #redirect_to users_path
    else
      @user.destroy
      flash[:success] = "User deleted."
      #redirect_to users_url
    end
    redirect_to users_path
  end

  def edit
    #@user = User.find(params[:id])
  end

  def update
    #@user = User.find(params[:id])
    if @user.update_attributes(user_params)
      flash[:success] = "Profile updated"
      redirect_to @user
    else
      render 'edit'
    end
  end

  private

   def user_params
     params.require(:user).permit(:name, :email, :password, :password_confirmation)
   end

    #Before filters

    def signed_in_user
      unless signed_in?
        store_location
        redirect_to signin_url, notice: "Please sign in." 
      end
    end

    def signed_in_user_filter 
      redirect_to root_path, notice: "Already logged in" if signed_in?
    end

    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url) unless current_user?(@user)
    end

    def admin_user
      redirect_to(root_url) unless current_user.admin?
    end

end

I'm not sure what else would be releveant but here's app/views/users/new.html.erb:

<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="span6 offset3">
    <%= form_for(@user) do |f| %>
      <%= render 'shared/error_messages', object: f.object %>
      <%= f.submit "Create my account", class: "btn btn-large btn-primary" %>
    <% end %>
  </div>
</div>

To be honest I'm not 100% sure where to look for this problem. It just happened with these latest changes I've made in this chapter. I try to do all the exercises so sometimes there's variation in what I'm supposed to edit so I don't know if I've messed something up or perhaps just done something dumb. When I visit the app from a browser, and click the "Sign me up" link to register a new user I get the red rails error page that says ActionController::ParameterMissing in UsersController#create but I don't know exactly what that means. I didn't really think I changed any code that would affect that, but I've tinkered around with some stuff to try to complete previous exercises so perhaps that's whats happening.

Thanks for any help! This is my first SO post so hopefully I didn't make a huge mistake in etiquette/formatting. I searched for someone with similar problems, as usual, but couldn't find anything.

Edit: I wanted to add that I've been working off the previous version of this tutorial as I wasn't done when the new edition came out. You can find it here: http://rails-4-0.railstutorial.org/book/user_microposts


Solution

  • I think the answer is pretty simple. It looks like you deleted all of the fields out of your form when he only wanted you to add in the error rendering component. Your sign-up form should be something like:

    <% provide(:title, 'Sign up') %>
    <h1>Sign up</h1>    
    <div class="row">
      <div class="span6 offset3">
        <%= form_for(@user) do |f| %>
         <%= render 'shared/error_messages', object: f.object %>
    
          <%= f.label :name %>
          <%= f.text_field :name %>
    
          <%= f.label :email %>
          <%= f.text_field :email %>
    
          <%= f.label :password %>
          <%= f.password_field :password %>
    
          <%= f.label :password_confirmation, "Confirmation" %>
          <%= f.password_field :password_confirmation %>
    
          <%= f.submit "Create my account", class: "btn btn-large btn-primary" %>
        <% end %>
      </div>
    </div>