Search code examples
ruby-on-rails-5

nav tabs used by two models and controllers with has_many and blongs_to


I have two models with has_many and belongs_to with nested resources and independent views. I have created nav-tabs which I wish to be rendered by both controllers. The nav-tabs works for trip view but does not work in location index. I need to pass local.. something to get working and I don't know how. This is the error I get. No route matches {:action=>"show", :controller=>"trips", :trip_id=>"13"} missing required keys: [:id] for this line: a.slow href=send("trip_url") Trip

Trip Model

class Trip < ApplicationRecord


  has_many :user_trips
  has_many :users, through: :user_trips, dependent: :destroy
  belongs_to :creator, class_name: "User"
  # has_many :locations, dependent: :destroy
  # belongs_to :location, optional: true, inverse_of: :locations
  has_many :locations

  accepts_nested_attributes_for :locations,  :reject_if => :all_blank, :allow_destroy => true

end

location model

class Location < ApplicationRecord
  # has_many :trips, inverse_of: :trips
  belongs_to :trip, optional: true
  # accepts_nested_attributes_for :trips,  :reject_if => :all_blank, :allow_destroy => true
end

Routes

Rails.application.routes.draw do

  resources :locations

  resources :trips do
    resources :locations
  end
end

trip controller

class TripsController < ApplicationController
  before_action :set_trip, only: [:show, :edit, :update, :destroy]

  # GET /trips
  # GET /trips.json
  def index
    @trips = Trip.all
  end

  # GET /trips/1
  # GET /trips/1.json
  def show
  end

  # GET /trips/new
  def new
    @user = current_user
    @trip = current_user.trips.build
  end

  # GET /trips/1/edit
  def edit
    @user = current_user
  end

  # POST /trips
  # POST /trips.json
  def create
    @user = current_user
    @trip = current_user.trips.build(trip_params)

    respond_to do |format|
      if @trip.save
        # @trip.users << @user
        format.html { redirect_to @trip, notice: 'Trip was successfully created.' }
        format.json { render :show, status: :created, location: @trip }
      else
        format.html { render :new }
        format.json { render json: @trip.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /trips/1
  # PATCH/PUT /trips/1.json
  def update
    respond_to do |format|
      if @trip.update(trip_params)
        format.html { redirect_to @trip, notice: 'Trip was successfully updated.' }
        format.json { render :show, status: :ok, location: @trip }
      else
        format.html { render :edit }
        format.json { render json: @trip.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /trips/1
  # DELETE /trips/1.json
  def destroy
    @trip.destroy
    respond_to do |format|
      format.html { redirect_to trips_url, notice: 'Trip was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_trip
      @trip = Trip.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def trip_params
      params.require(:trip).permit(:name, :description, :creator_id, :location_id, user_ids: [])
    end
end

location controller

class LocationsController < ApplicationController
  # before_action :set_location, only: [:show, :edit, :update, :destroy]
  # before_action :set_trip

  # GET /locations
  # GET /locations.json
  def index
    trip = Trip.find(params[:trip_id])
    @locations = trip.locations
    # @locations = trip.locations
  end

  # GET /locations/1
  # GET /locations/1.json
  def show
    @trip = Trip.find(params[:trip_id])
    trip = Trip.find(params[:trip_id])
    @location = trip.locations.find(params[:id])
  end

  # GET /locations/new
  def new
    trip = Trip.find(params[:trip_id])
    @location = trip.locations.build
  end

  # GET /locations/1/edit
  def edit
    trip = Trip.find(params[:trip_id])
    #2nd you retrieve the comment thanks to params[:id]

    @location = trip.locations.find(params[:id])

  end

  # POST /locations
  # POST /locations.json
  def create
    # @location = Location.new(location_params)
    trip = Trip.find(params[:trip_id])
    @location = trip.locations.create(params[:location_params])
    respond_to do |format|
      if @location.save
        format.html { redirect_to trip_locations_url, notice: 'Location was successfully created.' }
        format.json { render :show, status: :created, location: @location }
      else
        format.html { render :new }
        format.json { render json: @location.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /locations/1
  # PATCH/PUT /locations/1.json
  def update
    trip = Trip.find(params[:trip_id])
    @location = trip.locations.find(params[:id])
    respond_to do |format|
      if @location.update(location_params)
        format.html { redirect_to trip_locations_url, notice: 'Location was successfully updated.' }
        format.json { render :show, status: :ok, location: @location }
      else
        format.html { render :edit }
        format.json { render json: @location.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /locations/1
  # DELETE /locations/1.json
  def destroy
    trip = Trip.find(params[:trip_id])
    @location = trip.locations.find(params[:id])
    @location.destroy
    respond_to do |format|
      format.html { redirect_to trip_locations_url, notice: 'Location was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_trip
      trip = Trip.find(params[:trip_id])
    end

    # def set_location
    #   trip = Trip.find(params[:trip_id])
    #   @location = trip.locations.find(params[:id])
    #   # @location = Location.find(params[:id])
    # end
    # post = Post.find(params[:post_id])
    # #2nd you retrieve the comment thanks to params[:id]
    #
    # @comment = post.comments.find(params[:id])
    #

    # Never trust parameters from the scary internet, only allow the white list through.
    def location_params
      params.require(:location).permit(:name, :image, :street_address_1, :street_address_2, :city, :state, :zip_code, :country_code, :trip_id)
    end
end

Nav-tab

view/nav/_tabs.html.slim
    - if can?(:read, @trip)

  - controller = params[:controller].singularize
  ul.nav.nav-tabs#tabs
      li class=('active' if params[:action] == 'show')
        = link_to 'Trip', trip_path(@trip)

      li class=('active' if params[:action] == 'index')
        = link_to 'Location', trip_locations_url(@trip)

      li class=('active' if params[:action] == 'inex')
        = link_to 'Members'

      li class=('active' if params[:action] == 'index')
        = link_to 'Events'

      li class=('active' if params[:action] == 'index')
        = link_to 'Status'

location index view

header.intro-location
  .intro-body
    .container
      .row
        .col-md-18
          h1.brand-heading
            = render 'nav/tabs'
            h1.space-above Locations

            -if can?(:create, @locations)
            = link_to "Add New Location", new_trip_location_path, class: 'btn btn-xs btn-primary space-right'

            table.table.table-striped-location.table-hover-location.space-above
              thead
                tr
                  th Name
                  th Image
                  th Street address 1
                  th Street address 2
                  th City
                  th State
                  th Zip code
                  th Country code
                  th
                  th
                  th

              tbody
                - @locations.each do |location|
                  tr
                    td = location.name
                    td = location.image
                    td = location.street_address_1
                    td = location.street_address_2
                    td = location.city
                    td = location.state
                    td = location.zip_code
                    td = location.country_code
                    td = link_to 'Show', trip_location_url(location.trip, location), class: 'btn btn-xs btn-success space-right'
                    td = link_to 'Edit', edit_trip_location_url(location.trip, location), class: 'btn btn-xs btn-primary space-right'
                    td = link_to 'Destroy', [location.trip, location], data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-xs btn-danger space-right'

trip show view

p#notice = notice
header.intro-location
  .intro-body
    .container
      .row
        .col-md-14
          h3.brand-heading
            = render 'nav/tabs'
        .col-md-6.h4
          table.table.table-striped-location.table-hover-location.space-above
            thead
              tr
                th Name:
                td.show = @trip.name
              tr
                th Description:
                td.show = @trip.description


      => link_to 'Edit', edit_trip_path(@trip), class: 'btn btn-xs btn-primary space-right'
      '|
      =< link_to 'Back', trips_path, class: 'btn btn-xs btn-info space-right'

Solution

  • Updated the nav-bar

    - if can?(:read, @trip)
    
      - controller = params[:controller].singularize
      ul.nav.nav-tabs#tabs
          li class=('active' if params[:action] == 'show')
            = link_to 'Trip', trip_path(@trip)
    
          li class=('active' if params[:action] == 'index')
            = link_to 'Location', trip_locations_url(@trip)
    
          li class=('active' if params[:action] == 'inex')
            = link_to 'Members'
    
          li class=('active' if params[:action] == 'index')
            = link_to 'Events'
    
          li class=('active' if params[:action] == 'index')
            = link_to 'Status'
    

    Added @trip to location/index controller class LocationsController < ApplicationController

    def index
        @trip = Trip.find(params[:trip_id])
        trip = Trip.find(params[:trip_id])
        @locations = trip.locations
        # @locations = trip.locations
      end