I'm making my first Rails application and mistakes abound. I've searched for "no route matches" questions, but I couldn't find one that fit my problem.
I have a User model. It has_many :tasks and it has_one :pet. Both Task and Pet models belong_to :user. Task and Pet have no pages of their own, they appear on User's page. With Task, this works fine. Here's the show action in users_controller.rb
def show
@user = User.find(params[:id])
@tasks = @user.tasks.paginate(page: params[:page])
@pet = @user.pet
end
I have a feed of @tasks on the @user show.html.erb page, as well as a form for creating tasks. I also have a form for creating a @pet. However, when I click the submit button on the @pet creation form, it goes to an error page.
Routing Error. No route matches [PATCH] "/pet/1"
Strangely, looking at the routes, I see this:
tasks POST /tasks(.:format) tasks#create
task DELETE /tasks/:id(.:format) tasks#destroy
pet_index POST /pet(.:format) pet#create
pet DELETE /pet/:id(.:format) pet#destroy
root GET / static_pages#home
pet#create has the address pet_index, even though I certainly did not do that on purpose. A user only has one pet, a pet index would make no sense. I created the Pets model in the same way I did the Tasks model, but somewhere, something went wrong. The differences between the two have to do with the fact that there are several @tasks that are created and destroyed, while the pet is just one.
Here is pets_controller.rb
class PetsController < ApplicationController
before_action :signed_in_user
def create
@pet = current_user.build_pet(pet_params)
if @pet.save
flash[:success] = "Your pet is ready!"
redirect_to root_url
else
render 'static_pages/home'
end
end
def destroy
end
private
def pet_params
params.require(:pet).permit(:nome)
end
end
I also have a shared/_pet.html.erb partial which contains code that can't access the user.
<%= @user.pet.nil? ? "Pet name" : @user.pet.name %>
If I put
<%= render 'shared/pet' %>
in home.html.erb, it gives me this error:
NoMethodError in StaticPages#home. undefined method `pet' for nil:NilClass
It's a mess. I appreciate any help.
EDIT: Here's the pet creation form, in shared/pet_form.html.erb
<%= form_for(@pet) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :name, placeholder: "Give your pet a name." %>
</div>
<%= f.submit "Meet pet", class: "btn btn-small btn-default" %>
<% end %>
EDIT 2: Here's config/routes.rb
Petrefa::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :tasks, only: [:create, :destroy]
resources :pet, only: [:create, :destroy]
root 'static_pages#home'
match '/register', to: 'users#new', via: 'get'
match '/help', to: 'static_pages#help', via: 'get'
match '/developers', to: 'static_pages#about', via: 'get'
match '/login', to: 'sessions#new', via: 'get'
match '/logout', to: 'sessions#destroy', via: 'delete'
end
EDIT 3: After having changed form_for(@pet) do into form_for(@pet, method: :create, action: '/pet') do this is the resulting HTML
<form accept-charset="UTF-8" action="/pet/1" class="edit_pet" id="edit_pet_1" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓"><input name="_method" type="hidden" value="create"><input name="authenticity_token" type="hidden" value="fC/PjvsGPG1sKSGvzFSFfzSKAhUZv99w6fkmiRkLRU0="></div>
<div class="field">
<textarea id="pet_nome" name="pet[nome]" placeholder="Dê um nome para o seu petRefa.">fulano</textarea>
</div>
<input class="btn btn-small btn-default" name="commit" type="submit" value="Conhecer pet">
</form>
First, if you want to create a pet, you should use POST and not PATCH request. A POST request will be redirected to the create method, whereas a PATCH request will be redirected to the update method, which doesn't exist and has no route for it in your
PetsController. You can specify which action (like POST or PATCH) to use in the HTML form.Secondly, are you sure that you set
@userinStaticPages#home? That could be the reason for theundefined method `pet' for nil:NilClass`.Also, I think that to render a partial, you should use
<%= render partial: 'shared/pet' %>