mLuby
mLuby

Reputation: 703

No route matches {:controller

I've read over 20 StackOverflow pieces (and plenty others across the web) on very similar issues and tried their solutions, but none of it has worked. Please help this beginner!

In particular, the solution I've found most often is

form_for [@parent, @child] do |f|

but it doesn't fix the error the way it did for other people.

Error:

The error occurs at localhost:3000/locations/1/restaurants/new

NoMethodError in Restaurants#new

Showing /app/views/restaurants/_form.html.erb where line #1 raised:

undefined method `restaurants_path' for #<#<Class:0x007fb7ab89ea80>:0x007fb7aaadc3c0>

Extracted source (around line #1):

1: <%= form_for [@location, @restaurant] do |f| %>
2:   <% if @restaurant.errors.any? %>
3:     <div id="error_explanation">
4:       <h2><%= pluralize(@restaurant.errors.count, "error") %> prohibited this restaurant from being saved:</h2> 

I can't find any mention of restaurants_path in any of the app code, so I'm assuming it's some magical Rails default.

Code:

I'm using has_many/belongs_to models: A location has many restaurants.

config/routes.rb

  resources :locations do
    resources :restaurants
  end

$ rake routes

location_restaurants GET    /locations/:location_id/restaurants(.:format)          restaurants#index
                         POST   /locations/:location_id/restaurants(.:format)          restaurants#create
new_location_restaurant GET    /locations/:location_id/restaurants/new(.:format)      restaurants#new
edit_location_restaurant GET    /locations/:location_id/restaurants/:id/edit(.:format) restaurants#edit
location_restaurant GET    /locations/:location_id/restaurants/:id(.:format)      restaurants#show
                         PUT    /locations/:location_id/restaurants/:id(.:format)      restaurants#update
                         DELETE /locations/:location_id/restaurants/:id(.:format)      restaurants#destroy

app/controllers/restaurants_controller.rb

  def new
    @restaurant = Restaurant.new

    respond_to do |format|
      format.html
      format.json { render json: @restaurant }
    end
  end

  def edit
    @restaurant = Restaurant.find(params[:id])
  end

  def create
    @location = Location.find(params[:location_id])
    @restaurant = @location.restaurants.create(params[:restaurant])

    respond_to do |format|
      if @restaurant.save
    format.html { redirect_to location_restaurants_path(@location), notice: 'Restaurant was successfully created.' }
        format.json { render json: @restaurant, status: :created, location: @restaurant }
      else
        format.html { render action: "new" }
        format.json { render json: @restaurant.errors, status: :unprocessable_entity }
      end
    end
  end

Upvotes: 2

Views: 250

Answers (2)

Chris Salzberg
Chris Salzberg

Reputation: 27374

You have not initialized a @location, which is required for your form (in the line form_for [@location, @restaurant]). Just add a line that looks it up (using Location.find) to your new action and then build @restaurant so that it is associated with the location:

def new
  @location = Location.find(params[:location_id])
  @restaurant = @location.restaurants.build
  ...

end

Since you'll need @location for all your actions (including edit, which I assume must not be working either in your current code), it would make sense to put it into a separate method and then call it from a before_filter, i.e.:

before_filter :find_location

private

def find_location
  @location = Location.find(params[:location_id])
end

Then you can also remove the line where you find the location in your create action (and from the new action).

Upvotes: 1

kries
kries

Reputation: 199

I believe the issue is the way you are instantiating the @restaurant variable in the new action. Because it is nested under locations, you need to build it as such:

@location = Location.find(params[:location_id]) @restaurant = @location.restaurants.new

Upvotes: 0

Related Questions