Hi I am trying to create a relationship between two models Establishments and OpenClosed I have added
class Establishment < ApplicationRecord
has_many :open_closed
end
class OpenClosed < ApplicationRecord
belongs_to :establishment
end
I have added establishment_id field to open_closed table and then ran rails db:migrate.Next I've nested the resources
resources :establishments do
resources :open_closeds
end
Then I modified the OpenClosed controller #new line comment where I've added new code
def new
@establishment = Establishment.find(params[:establishment_id]) #new line added
@open_closed = OpenClosed.new
end
# GET /open_closeds/1/edit
def edit
end
# POST /open_closeds
# POST /open_closeds.json
def create
@establishment = Establishment.find(params[:establishment_id]) #new line added
@open_closed = OpenClosed.new(open_closed_params)
@open_closed.Establishment = @establishments #new line added
respond_to do |format|
if @open_closed.save
format.html { redirect_to @open_closed, notice: 'Open closed was successfully created.' }
format.json { render :show, status: :created, location: @open_closed }
else
format.html { render :new }
format.json { render json: @open_closed.errors, status: :unprocessable_entity }
end
end
end
This is the error I'm getting when I submit form in open_closed view:
undefined method `Establishment=' for # Did you mean? establishment= establishment establishment_id= establishment_id establishment_id?
Can not for the life of me work out where I'm going wrong here could someone please point me in the right direction with this one many thanks in advance.
First, rewrite the OpenClosed#new
action to look like this:
<h1>New Open Closed</h1>
<%= render 'form', establishment: @establishment, open_closed: @open_closed %>
<%= link_to 'Back', establishment_open_closeds_path %>
This means we are now passing in an Establishment
object and a OpenClosed
object to the form partial.
Next, change the <%= form_for ... %>
declaration at
`app/views/open_closeds/_form.html.erb`
to look like this:
<%= form_for [establishment, open_closed] do |f| %>
We've just told our form to use both the Establishment
and OpenClosed
object.
Next, rewrite the open_closed controller to look like this:
def create
@establishment = Establishment.find(params[:establishment_id])
@open_closed = OpenClosed.new(open_closed_params)
@open_closed.Establishment = @establishment #new line added
respond_to do |format|
if @open_closed.save
format.html { redirect_to [@establishment, @open_closed], notice: 'Open closed was successfully created.' }
format.json { render :show, status: :created, location: @open_closed }
else
format.html { render :new }
format.json { render json: @open_closed.errors, status: :unprocessable_entity }
end
end
end
The two modifications I made were:
changing the line
@open_closed.Establishment = @establishments
to
@open_closed.establishment = @establishment
Note that the 'e' in establishment is now lowercase and I removed the 's' at the end of the line (that was probably just a typo). If you look at your db/schema.rb
file, you should see
t.integer "establishment_id"
under the open_closeds
table. In ActiveRecord, you access the methods of your class using the same name as the row in your database table. However, for foreign keys like establishment_id
, rails is smart enough to know that when you say @open_closed.establishment
, you really just want the Establishment
that belongs to your OpenClosed
object.
The second thing I changed in the above code is this line:
redirect_to [@establishment, @open_closed] ...
You need to provide both the establishment and open_closed objects in order for the route to be valid. Since the redirect statement is sending you to the show method of the OpenClosed class, you can run rake routes to see what the route for OpenClosed#show
looks like. I ran rake routes
on your route file and got this for the show method of OpenClosed
establishment_open_closed GET /establishments/:establishment_id/open_closeds/:id(.:format) open_closeds#show
So you can see that OpenClosed#show
is expecting both an Establishment object and an OpenClosed object. You simply need to provide both objects in an array as the first parameter to redirect_to
You will likely still get an error when you try this because many of the routes in the application are incorrect and need to changed. For example, to actually render the OpenClosed#show
view (which is where you're redirected after a successful call to OpenClosed#create
), you will need to make the following modifications to the show template of the OpenClosed controller:
<p id="notice"><%= notice %></p>
<%= link_to 'Edit', edit_establishment_open_closed_path(@open_closed) %> |
<%= link_to 'Back', establishment_open_closeds_path %>
As a tip for the future, you can add
<%= debug(params) if Rails.env.development? %>
in your app/views/layouts/application.html.erb
file directly after the yield. This will print out server response information which can useful when debugging.
Lastly, there are going to be other parts of you application that won't work until you fix the routes, but hopefully you have enough info to do that now.
For more information on nested routes, check out the official rails guids
Happing coding!