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
@user
inStaticPages#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' %>