Reputation: 403
Spent the last day and a half scouring through the great threads here at SO and reading other things online and I'm still having trouble grasping the solution and how these moving pieces operate together.
I have a many-to-many relationship between County and TownshipRange through CountyTownshipRangeSurvey. This relationship is indicated in the routes file through nested resources.
I want the user to be able to delete the association between the two records, but the problem I'm running into is the delete link on the TownshipRange index page only accepts the township_range id value and not the associated county id value. Note that the correct county id param is present when viewing the index page (which contains the delete link).
How can I allow for this?
My hunch is that I need to make a change in two place. First, to the routes file so it will accept the county id and second, to the link_to in the view.
As a follow-up question... I realize I'm trying to put the functionality into the township_ranges_controller. Is this part of the problem? Would I be better served to move this functionality into a separate controller dedicated solely to the creation of the "through table" associations?
Thank you all for your invaluable insights! If you need any more code snippets, please let me know!
Model county.rb
class County < ApplicationRecord
has_many :township_ranges, through: :county_township_range_surveys
has_many :county_township_range_surveys
...
end
Model township_range.rb
class TownshipRange < ApplicationRecord
has_many :counties, through: :county_township_range_surveys
has_many :county_township_range_surveys
...
end
Model county_township_range_survey.rb
class CountyTownshipRangeSurvey < ApplicationRecord
belongs_to :county
belongs_to :township_range
...
end
Controller township_ranges_controller.rb
before_action :set_township_range, only: [:show, :edit, :update, :destroy]
...
# QUESTION: How do I find the appropriate county?
def destroy
@county = County.find(params[:id]) # This does not work
@county.township_ranges.destroy(@township_range)
redirect_to township_ranges_path(@county)
flash[:success] = "Township and Range has been deleted"
end
....
private
def set_township_range
@township_range = TownshipRange.find(params[:id])
end
...
related portion of routes.rb (expanded 20161124)
resources :states, shallow: true do
resources :counties do
resources :township_ranges do
resources :sections
end
end
end
Rails routes indicates the generated route does not look for the associated counties/:id for the DELETE action.
township_ranges GET /counties/:id/township_ranges(.:format) township_ranges#index
POST /counties/:id/township_ranges(.:format) township_ranges#create
new_township_range GET /counties/:id/township_ranges/new(.:format) township_ranges#new
edit_township_range GET /township_ranges/:id/edit(.:format) township_ranges#edit
township_range GET /township_ranges/:id(.:format) township_ranges#show
PATCH /township_ranges/:id(.:format) township_ranges#update
PUT /township_ranges/:id(.:format) township_ranges#update
DELETE /township_ranges/:id(.:format) township_ranges#destroy
It will look for the full route DELETE counties/:county_id/township_range/:id/
if I isolate the nesting by itself like this
resources :counties do
resources :township_ranges
end
but that keeps counties from being nested under states, which is not what I'm after...
township_range/index.html.erb
<td><%= link_to 'Destroy', township_range, method: :delete,
data: { confirm: "Delete #{township_range.township}
#{township_range.range} ?" } %></td>
development.log (with link update as requested by @Wish Zone)
Started GET "/counties/25/township_ranges" for 127.0.0.1 at 2016-11-23 15:23:20 -0600
Processing by TownshipRangesController#index as HTML
Parameters: {"id"=>"25"}
[1m[36mCounty Load (0.1ms)[0m [1m[34mSELECT "counties".* FROM "counties" WHERE "counties"."id" = ? LIMIT ?[0m [["id", 25], ["LIMIT", 1]]
Rendering township_ranges/index.html.erb within layouts/application
[1m[36mTownshipRange Load (34.5ms)[0m [1m[34mSELECT "township_ranges".* FROM "township_ranges" INNER JOIN "county_township_range_surveys" ON "township_ranges"."id" = "county_township_range_surveys"."township_range_id" WHERE "county_township_range_surveys"."county_id" = ?[0m [["county_id", 25]]
Rendered township_ranges/index.html.erb within layouts/application (72.6ms)
Completed 500 Internal Server Error in 113ms (ActiveRecord: 35.2ms)
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"township_ranges", :county_id=>#<County id: 25, name: "comanche", abbreviation: nil, state_id: 35, created_at: "2016-11-22 16:24:52", updated_at: "2016-11-22 16:24:52">, :id=>nil} missing required keys: [:id]):
22: <td><%= link_to 'Edit', edit_township_range_path(township_range) %></td>
23: <%# QUESTION: Do I need to modify the link here so it somehow takes in the county id param? %>
24: <%# NOTE: This will likely also require some sort of customization to the routes file so that the county_id is passed as a param %>
25: <td><%= link_to 'Destroy', township_range_path(id: @township_range, county_id: @county), method: :delete,
26: data: { confirm: "Delete #{township_range.township} #{township_range.range} ?" } %></td>
27: </tr>
28: <% end %>
Upvotes: 1
Views: 878
Reputation: 1531
According to your situation Route should be
township_range_path(id: @township_range , county_id: @county)
and in controller you can find
County.find(params[:county_id])
Added by Spectator6: The final answer ended up being to remove the member do's I originally had in my routes. The working delete path ended up being
township_range_path(id: township_range, county_id: @county)
Thanks again @Wish Zone for your patience and for helping me understand the link_to path and routes a bit better :)
Upvotes: 2