I am having an issue with creating nested resources in my admin namespace. I am somewhat new to namespaces. I have read several posts on Stack but to no avail, perhaps i am implementing this incorrectly.
I have an admin model (devise), and am trying to nest an address to the custom user show page I have created, this is where the problem is.
When trying to create a new address for an admin I get this error when I submit the form:
ActionController::UrlGenerationError at /admin/admins/2CE0/addresses
No route matches {:action=>"show", :admin_id=>"2CE0", :controller=>"admin/admins/admin/addresses"} missing required keys: [:id]
A Screen Shot of the Better Errors Page:
My Routes.rb
namespace :admin do
devise_for :admins, controllers: { sessions: 'admin/admins/sessions', passwords: 'admin/admins/passwords', registrations: 'admin/admins/registrations', confirmations: 'admin/admins/confirmations', unlocks: 'admin/admins/unlocks', shared: 'admin/admins/shared' }
resources :admins, controller: 'admins/admin', shallow: true do
resources :addresses, except: [:index], controller: 'admins/admin/addresses'
end
end
###Admin Authentication Scope###
devise_scope :admin do
authenticated do
root to: 'admin/admin_static#home', as: 'authenticated_admin'
end
end
Rake Routes Output:
admin_admin_addresses POST /admin/admins/:admin_id/addresses(.:format) admin/admins/admin/addresses#create
new_admin_admin_address GET /admin/admins/:admin_id/addresses/new(.:format) admin/admins/admin/addresses#new
edit_admin_address GET /admin/addresses/:id/edit(.:format) admin/admins/admin/addresses#edit
admin_address GET /admin/addresses/:id(.:format) admin/admins/admin/addresses#show
PATCH /admin/addresses/:id(.:format) admin/admins/admin/addresses#update
PUT /admin/addresses/:id(.:format) admin/admins/admin/addresses#update
DELETE /admin/addresses/:id(.:format) admin/admins/admin/addresses#destroy
The Admin Model:
class Admin < ActiveRecord::Base
before_create :generate_admin_ident
# Devise Modules
devise :database_authenticatable, :registerable,:recoverable, :rememberable,
:trackable, :validatable, :confirmable, :lockable, :timeoutable
# Model Relationships
has_many :addresses, dependent: :destroy
# Model Validations
validates_uniqueness_of :admin_ident
#Unique Identifier Generation
def generate_admin_ident
begin
self.admin_ident = SecureRandom.hex(2).upcase
other_admin = Admin.find_by(admin_ident: self.admin_ident)
end while other_admin
end
# Vanity URL
def to_param
admin_ident
end
end
The Admin Controller: - Note this only controls a custom admin index and show page
class Admin::Admins::AdminController < ApplicationController
before_action :authenticate_admin_admin!
def index
@admins = Admin.all
end
def show
@admin = Admin.find_by_admin_ident(params[:id])
@addresses = @admin.addresses
end
def new
end
def edit
end
def create
end
def update
end
def destroy
end
end
The Address Model:
class Address < ActiveRecord::Base
before_create :generate_address_ident
# Model Relationships
belongs_to :admin
# Model Validations
validates_uniqueness_of :address_ident
#Unique Identifier Generation
def generate_address_ident
begin
self.address_ident = SecureRandom.hex(4).upcase
other_address = Address.find_by(address_ident: self.address_ident)
end while other_address
end
# Vanity URL
def to_param
address_ident
end
end
The Address Controller:
class Admin::Admins::Admin::AddressesController < ApplicationController
before_action :authenticate_admin_admin!
before_action :set_address, only: [:show, :edit, :update, :destroy]
# GET /addresses
# GET /addresses.json
def index
@addresses = Address.all
end
# GET /addresses/1
# GET /addresses/1.json
def show
end
# GET /addresses/new
def new
@admin = Admin.find(params[:admin_id])
@address = Address.new
end
# GET /addresses/1/edit
def edit
end
# POST /addresses
# POST /addresses.json
def create
@admin = Admin.find_by_id(params[:admin_id])
@address = Address.new(address_params)
respond_to do |format|
if @address.save
format.html { redirect_to admin_admin_address_url[:admin, @admins, @address], notice: 'Address was successfully created.' }
format.json { render :show, status: :created, location: @address }
else
format.html { render :new }
format.json { render json: @address.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /addresses/1
# PATCH/PUT /addresses/1.json
def update
respond_to do |format|
if @address.update(address_params)
format.html { redirect_to @address, notice: 'Address was successfully updated.' }
format.json { render :show, status: :ok, location: @address }
else
format.html { render :edit }
format.json { render json: @address.errors, status: :unprocessable_entity }
end
end
end
# DELETE /addresses/1
# DELETE /addresses/1.json
def destroy
@address.destroy
respond_to do |format|
format.html { redirect_to addresses_url, notice: 'Address was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_address
@address = Address.find_by_address_ident(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def address_params
params.require(:address).permit(:admin_id, :street_number, :street_name, :street_type, :grid, :city, :province, :postal_code, :current)
end
end
And Finally the Rails Server Console output when trying co create a new admin address:
Started POST "/admin/admins/2CE0/addresses" for ::1 at 2016-05-25 22:54:40 -0600
Processing by Admin::Admins::Admin::AddressesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"i+B7DS85BtWIA9xsAQnzPByayTZ9Z4fI4rTkEcBqfgkQw9CFTFUMaRhUDyQKYgzA9SPNYWJIkyU8lcnyODYKuw==", "address"=>{"admin_id"=>"", "street_number"=>"1234", "street_name"=>"something", "street_type"=>"AVE", "grid"=>"NW", "city"=>"YYC", "province"=>"AB", "postal_code"=>"123 456", "current"=>"0"}, "commit"=>"Create Address", "admin_id"=>"2CE0"}
Admin Load (0.2ms) SELECT "admins".* FROM "admins" WHERE "admins"."id" = $1 ORDER BY "admins"."id" ASC LIMIT 1 [["id", 1]]
Admin Load (0.4ms) SELECT "admins".* FROM "admins" WHERE "admins"."id" = $1 LIMIT 1 [["id", 2]]
(0.1ms) BEGIN
Address Exists (0.2ms) SELECT 1 AS one FROM "addresses" WHERE "addresses"."address_ident" IS NULL LIMIT 1
Address Load (0.1ms) SELECT "addresses".* FROM "addresses" WHERE "addresses"."address_ident" = $1 LIMIT 1 [["address_ident", "1F185CE6"]]
SQL (0.1ms) INSERT INTO "addresses" ("street_number", "street_name", "street_type", "grid", "city", "province", "postal_code", "current", "created_at", "updated_at", "address_ident") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING "id" [["street_number", "1234"], ["street_name", "something"], ["street_type", "AVE"], ["grid", "NW"], ["city", "YYC"], ["province", "AB"], ["postal_code", "123 456"], ["current", "f"], ["created_at", "2016-05-26 04:54:40.377296"], ["updated_at", "2016-05-26 04:54:40.377296"], ["address_ident", "1F185CE6"]]
(5.9ms) COMMIT
Completed 500 Internal Server Error in 39ms (ActiveRecord: 9.5ms)
ActionController::UrlGenerationError - No route matches {:action=>"show", :admin_id=>"2CE0", :controller=>"admin/admins/admin/addresses"} missing required keys: [:id]:
Thank you all in advance, I am in a bind here and not sure where I fell down the Rabbit hole! Please ask if you need more information, I have tried to provide as much as possible!
If you are new to name spacing, I'd recommend creating a new app, and then using a scaffold generator to create an address in an admin names space. Then look at the way the scaffold builds the objects, and compare that to what you have.
Scaffold will build the files in the way the rails developers expect them to be built, and that should show you how to do it.