0

Good day StackOverflow,

I have created an admin namespace, and within the namespace I have a client resource and nested in that is a site resource like so:

# routes.rb

namespace :admin do

  resouurces :clients do
    resources :sites
  end

end

I am running into the following error when attempting to go from the "site" show page to the site "edit" page:

ActionController::UrlGenerationError at /admin/clients/9A81622C/sites/88AA/edit

and then BetterErrors gives me this below the error message:

No route matches {:action=>"show", :client_id=>nil, :controller=>"admin/clients/sites", :id=>"88AA"} missing required keys: [:client_id]

the rake routes output for the admin_client_site is as follows:

     admin_client_sites POST   /admin/clients/:client_id/sites(.:format)          admin/clients/sites#create
  new_admin_client_site GET    /admin/clients/:client_id/sites/new(.:format)      admin/clients/sites#new
 edit_admin_client_site GET    /admin/clients/:client_id/sites/:id/edit(.:format) admin/clients/sites#edit
      admin_client_site GET    /admin/clients/:client_id/sites/:id(.:format)      admin/clients/sites#show
                        PATCH  /admin/clients/:client_id/sites/:id(.:format)      admin/clients/sites#update
                        PUT    /admin/clients/:client_id/sites/:id(.:format)      admin/clients/sites#update
                        DELETE /admin/clients/:client_id/sites/:id(.:format)      admin/clients/sites#destroy

the edit link on the "show page" is currently as follows, and this is where the problem lies(or so I believe):

<%= link_to "Edit", edit_admin_client_site_path(@client, @site) %>

the form_for for client, sites is:

<%= form_for [:admin, @client, @site], :url => admin_client_sites_url do |f| %>

I Have spent the last day looking at various stack answers and still can not sort this out, any help here is greatly appreciated, thanks in advance and please let me know if you need any more documentation!

EDIT # 1 - Adds Client and Site Models

Client.rb
class Client < ActiveRecord::Base
  before_create :generate_client_ident

    # Model Relations
    has_many :sites, dependent: :destroy

    # Model Validations
    validates_uniqueness_of :client_ident

    # Unique Admin Identifier
    def generate_client_ident
      begin
        self.client_ident = SecureRandom.hex(4).upcase
        other_client = Client.find_by(client_ident: self.client_ident)
      end while other_client
    end

    # Vanity URL
    def to_param
      client_ident
    end
end


Site.rb
class Site < ActiveRecord::Base
  before_create :generate_site_ident

  # Model Relations
  belongs_to :client

  # Model Validations
  validates_uniqueness_of :site_ident

  # Unique Admin Identifier
  def generate_site_ident
    begin
      self.site_ident = SecureRandom.hex(2).upcase
      other_site = Site.find_by(site_ident: self.site_ident)
    end while other_site
  end

  # Vanity URL
  def to_param
    site_ident
  end

end

EDIT #2 - Adds Controllers

class Admin::Clients::SitesController < ApplicationController
  before_action :authenticate_admin_admin!
  before_action :set_site, only: [:show, :edit, :update, :destroy]

  # GET /sites
  # GET /sites.json
  def index
    @sites = Site.all
  end

  # GET /sites/1
  # GET /sites/1.json
  def show
    @client = Client.find_by_client_ident(params[:id])
  end

  # GET /sites/new
  def new
    @client = Client.find_by_client_ident(params[:id])
    @site = Site.new
  end

  # GET /sites/1/edit
  def edit
    @client = Client.find_by_client_ident(params[:id])
  end

  # POST /sites
  # POST /sites.json
  def create
    @client = Client.find_by_client_ident(params[:id])
    @site = Site.new(site_params)
    @site.client = @client

    respond_to do |format|
      if @site.save
        format.html { redirect_to admin_clients_url, notice: 'Site was successfully created.' }
        format.json { render :show, status: :created, location: [:admin, @client] }
      else
        format.html { render :new }
        format.json { render json: @site.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /sites/1
  # PATCH/PUT /sites/1.json
  def update
    respond_to do |format|
      if @site.update(site_params)
        format.html { redirect_to [:admin, @client], notice: 'Site was successfully updated.' }
        format.json { render :show, status: :ok, location: [:admin, @client] }
      else
        format.html { render :edit }
        format.json { render json: @site.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /sites/1
  # DELETE /sites/1.json
  def destroy
    @site.destroy
    respond_to do |format|
      format.html { redirect_to sites_url, notice: 'Site was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_site
      @site = Site.find_by_site_ident(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def site_params
      params.require(:site).permit(:client_id, :site_ident)
    end
end

class Admin::ClientsController < ApplicationController
  before_action :authenticate_admin_admin!
  before_action :set_client, only: [:show, :edit, :update, :destroy]

  # GET /clients
  # GET /clients.json
  def index
    @clients = Client.all
  end

  # GET /clients/1
  # GET /clients/1.json
  def show
    @client = Client.find_by_client_ident(params[:id])
    @site = @client.sites
  end

  # GET /clients/new
  def new
    @client = Client.new
  end

  # GET /clients/1/edit
  def edit
  end

  # POST /clients
  # POST /clients.json
  def create
    @client = Client.new(client_params)

    respond_to do |format|
      if @client.save
        format.html { redirect_to [:admin, @client], notice: 'Client was successfully created.' }
        format.json { render :show, status: :created, location: @client }
      else
        format.html { render :new }
        format.json { render json: @client.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /clients/1
  # PATCH/PUT /clients/1.json
  def update
    respond_to do |format|
      if @client.update(client_params)
        format.html { redirect_to [:admin, @client], notice: 'Client was successfully updated.' }
        format.json { render :show, status: :ok, location: @client }
      else
        format.html { render :edit }
        format.json { render json: @client.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /clients/1
  # DELETE /clients/1.json
  def destroy
    @client.destroy
    respond_to do |format|
      format.html { redirect_to [:admin, @client], notice: 'Client was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_client
      @client = Client.find_by_client_ident(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def client_params
      params.fetch(:client, {}).permit(:client_ident, :client_name, :street_number, :street_name, :unit_apt, :grid, :city,
                             :province, :postal_code, :office_tel, :office_ext, :cell_tel, :fax, :contact_email, :same_as_above,
                             :bill_to_client_name, :bill_to_street_number, :bill_to_street_name, :bill_to_grid, :bill_to_city,
                             :bill_to_province, :bill_to_postal_code)
    end
end

EDIT #3 Adds ScreenShot Of Error enter image description here

EDIT #4 - Adds Rails Server Log when clicking the Edit link on the "Site Show Page"

Started GET "/admin/clients/9A81622C/sites/88AA" for ::1 at 2016-05-25 14:10:51 -0600
Processing by Admin::Clients::SitesController#show as HTML
  Parameters: {"client_id"=>"9A81622C", "id"=>"88AA"}
  Admin Load (0.4ms)  SELECT  "admins".* FROM "admins" WHERE "admins"."id" = $1  ORDER BY "admins"."id" ASC LIMIT 1  [["id", 1]]
  Site Load (0.2ms)  SELECT  "sites".* FROM "sites" WHERE "sites"."site_ident" = $1 LIMIT 1  [["site_ident", "88AA"]]
  Client Load (0.2ms)  SELECT  "clients".* FROM "clients" WHERE "clients"."id" = $1 LIMIT 1  [["id", 9]]
  Rendered admin/clients/sites/show.html.erb within layouts/application (3.4ms)
Completed 500 Internal Server Error in 12ms (ActiveRecord: 0.8ms)
Shawn Wilson
  • 1,311
  • 14
  • 40
  • Show, what is in your Admin::SitesController. Check if in edit action you assign @ client variable properly. The error says that @ client is nil - so edit_admin_client_site_path could not be generated because @ site must relate to @ client and cannot relate to nil client, obviously. – Alex May 25 '16 at 18:36
  • Ive Added the controllers, It appears that I have added the variable where it needs to be. – Shawn Wilson May 25 '16 at 18:43
  • My suggestion is to go deeper into debugging. Check what the value of @ client on the show action. Check what link rails generates. Check if request comes into edit action. – Alex May 25 '16 at 18:59

2 Answers2

0

It looks like the issue might be in your Sites controller. In looking over how you're trying to set @client I see that you have it as: @client = Client.find_by_client_ident(params[:id])

But at this level in the nesting params[:id] would be referencing the site's id, not the client's. Not knowing exactly how you're using/storing client_ident versus the actual id of the client I would have expected to see the following instead:

@client = Client.find_by_id(params[:client_id])

This is because in your routes you have the paths setup for .../clients/:client_id/sites/:site_id so the :client_id is what would be getting passed in. In this case when you try to look the client up in the Sites controller you're passing the site's id as the parameter rather than the client_id.

If your client_ident != client.id then I'd avoid trying to use the params[:id] to look up/load records by Client.find_by_client_ident as those shouldn't match up (unless, like I said, I'm missing something in how you implement client_ident).

Let us know your thoughts and if that change works for you :)

  • The client_ident is essentially just a vanity / replacement for the usual of id:1,2,3 ect.. but I want these placed in the url to make it harder for someone to jump around that may gain access to the app. – Shawn Wilson May 25 '16 at 19:06
  • i have also tried to impliment your fix, however am still receiving the same error, no changes to the original error. – Shawn Wilson May 25 '16 at 19:06
  • @ShawnWilson When you made the change, what did you change the `sites#show` action to? Can you throw a `byebug` or `binding.pry` (whichever you might be using) into the `sites#show` action and see what the value of @client is at that point? – marginalchaos May 25 '16 at 20:05
  • I changed the show action to reflect your @client = Client.find_by_id(params[:client_id]) and the link to edit on the show page is <%= link_to "Edit", edit_admin_client_site_path(@client, @site) %> and i still get the same error – Shawn Wilson May 25 '16 at 20:09
  • Is the current URL in the browser of the show page showing the `:client_ident` or `client_id`? If its showing the ident, value then we may have to use the following: `@client = Client.find_by_client_ident(params[:client_id])` While the value in the path might be the client_ident, rails (due to the routes) still sees that as the client_id for parameter purposes. (Fingers and toes crossed) – marginalchaos May 25 '16 at 20:12
  • when I go to the site show page i use http://localhost:3000/admin/clients/9A81622C/sites/88AA it sees this and wants to show the page but errors out due to the edit link on the page, if i remove the edit link, the page appears properly. – Shawn Wilson May 25 '16 at 20:14
  • So the error isn't when trying to click on follow the link but instead its when you try to load the show page it yells about that not being a valid path? – marginalchaos May 25 '16 at 20:15
  • yes, so i have just added your correction to the show page and it loads the show page now the edit page errors out but i believe i just need to address the links on the edit page, ill let you know if this has resolved this. – Shawn Wilson May 25 '16 at 20:17
  • Awesome! I hope it works for the other pages too, please let us know :) – marginalchaos May 25 '16 at 20:17
  • no I actually think im heading down a rabbit hole, im going to back it all out and rebuild this section.. i think the big issue is the nested resources in the admin namespace.. ive never worked with it in this way before.. ill rebuild and let you know when its done, perhaps give you access to the github to look for yourself? – Shawn Wilson May 25 '16 at 21:52
  • Ok So I have re worked the App, and am still having the same issue, i have started another Stack Question and here is the link : https://stackoverflow.com/questions/37452162/admin-namespace-with-nested-resources-not-saving take a look at that and if you want let me know and ill give you access to my repo – Shawn Wilson May 26 '16 at 06:12
0

I know this quesion was probably answered a long time ago.. but looking at your code I see an error here

resouurces :clients do

resources

sam
  • 355
  • 5
  • 10