I am pretty new to react on rails, I am sorry if this is something obvious! I know there are pages of this question, but none have fixed the error I am getting. Any advice is greatly appreciated!
When I submit a form from my assets Component my rails rails server returns-
ActionController::ParameterMissing (param is missing or the value is empty: asset):
app/controllers/api/assets_controller.rb:48:in `asset_params'
app/controllers/api/assets_controller.rb:14:in `create'
Route.rb
Rails.application.routes.draw do
mount_devise_token_auth_for 'User', at: 'api/auth'
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Defines the root path route ("/")
# root "articles#index"
namespace :api do
resources :areas do
resources :assets
end
end
end
model
class Asset < ApplicationRecord
belongs_to :area
validates :name, :description, :barcode, :price, :pdate, :status, :img, :category, presence: true
end
assets_controller
class Api::AssetsController < ApplicationController
before_action :set_area
before_action :set_asset, only: [:show, :update, :destroy]
def index
render json: @area.assets
end
def show
render json: @asset
end
def create
@asset = @area.assets.new(asset_params)
if @asset.save
render json: @asset
else
errKey = @asset.errors.messages.keys[0].to_s
errValue = @asset.errors.messages.values[0][0]
render json: {errors: "#{errKey} #{errValue}"}, status: :unprocessable_entity
end
end
def update
if @asset.update(asset_params)
render json:@asset
else
render json: {errors: @asset.errors }, status: :unprocessable_entity
end
end
def destroy
@asset.destroy
render json: {message: "Asset Deleted"}
end
private
def set_area
@area = Area.find(params[:area_id])
end
def set_asset
@asset = @area.assets.find(params[:id])
end
def asset_params
params.require(:asset).permit(:name, :description, :barcode, :price, :pdate, :status, :img, :category)
# params.fetch(:asset).permit(:name :description, :barcode, :price, :pdate, :status, :img, :category)
end
end
###Note when I use params.fetch I still get the same error
AssetProvider.js
import React, {useState } from 'react';
import axios from 'axios';
import {useNavigate} from 'react-router-dom';
export const AssetContext = React.createContext();
export const AssetConsumer = AssetContext.Consumer;
const AssetProvider = ({ children }) => {
const [assets, setAssets] = useState([])
const [errors, setErrors] = useState([])
const getAllAssets = (areaId) => {
axios.get(`/api/areas/${areaId}/assets`)
.then (res => setAssets(res.data))
.catch(err => {
setErrors({
variant: 'danger',
msg: err.response.data.errors.full_messages[0]
})
})
}
const addAsset = (areaId, asset) => {
axios.post(`/api/areas/${areaId}/assets`, { asset })
.then ( res => setAssets([...assets, res.data]))
.catch(err => {
setErrors({
variant: 'danger',
msg: Object.keys(err.response.data.errors)[0] + " " + Object.values(err.response.data.errors)[0][0]
})
})
}
const updateAsset = (areaId, id, asset) => {
axios.put (`/api/areas/${areaId}/assets/${id}`, {asset})
.then ( res => {
const newUpdatedAssets = assets.map(a => {
if (a.id === id) {
return res.data
}
return a
})
setAssets(newUpdatedAssets)
})
.catch(err => {
setErrors({
variant: 'danger',
msg: Object.keys(err.response.data.errors)[0] + " " + Object.values(err.response.data.errors)[0][0]
})
})
}
const deleteAsset = (areaId, id) => {
axios.delete(`/api/areas/${areaId}/assets/${id}`)
.then (res => {
setAssets(assets.filter(a => a.id !== id))
})
.catch(err => {
setErrors({
variant: 'danger',
msg: err.response.data.errors[0]
})
})
}
return (
<AssetContext.Provider value={{
assets,
errors,
setErrors,
getAllAssets,
addAsset,
updateAsset,
deleteAsset,
}}>
{children}
</AssetContext.Provider>
)
}
export default AssetProvider;
AssetForm.js
import { useState} from 'react'
import {Form, Button} from 'react-bootstrap'
import {AssetConsumer} from '../../providers/AssetProvider'
import { useParams} from 'react-router-dom'
const AssetForm = ({ setAdd, addAsset}) => {
const [asset, setAsset] = useState ({ name: '', img: '', barcode: '', description: '', category: '', price: '', pdate: '', status: ''})
const { areaId } = useParams();
const handleSubmit = (e) => {
e.preventDefault()
addAsset(areaId, asset)
setAdd(false)
setAsset({ name: '', img: '', barcode: '', description: '', category: '', price: '', pdate: '', status: ''})
}
return (
<>
<Form onSubmit={handleSubmit}>
<Form.Group className="mb-3" >
<Form.Label>Asset Image</Form.Label>
<Form.Control
name='img'
value={asset.img}
onChange={(e) => setAsset({...asset, img: e.targetvalue})}
/>
</Form.Group>
<Form.Group className="mb-3" >
<Form.Label>Name</Form.Label>
<Form.Control
name='name'
value={asset.name}
onChange={(e) => setAsset({...asset, name: e.targetvalue})}
autoFocus
required
/>
</Form.Group>
<Form.Group className="mb-3" >
<Form.Label>Barcode</Form.Label>
<Form.Control
name='barcode'
value={asset.barcode}
onChange={(e) => setAsset({...asset, barcode: e.targetvalue})}
/>
</Form.Group>
<Form.Group className="mb-3" >
<Form.Label>Description</Form.Label>
<Form.Control
name='description'
value={asset.description}
onChange={(e) => setAsset({...asset, description: e.targetvalue})}
as="textarea"
rows={3}
/>
</Form.Group>
<Form.Group className="mb-3" >
<Form.Label>Category</Form.Label>
<Form.Select name='category'
value={asset.category}
onChange={(e) => setAsset({...asset, category: e.targetvalue})}
>
<option>Select from list</option>
<option value="camera">Camera</option>
<option value="light">Light</option>
<option value="tripod">Tripod</option>
</Form.Select>
</Form.Group>
<Form.Group className="mb-3" >
<Form.Label>Price</Form.Label>
<Form.Control
name='price'
value={asset.price}
onChange={(e) => setAsset({...asset, price: e.targetvalue})}
/>
</Form.Group>
<Form.Group className="mb-3" >
<Form.Label>Purchase Date</Form.Label>
<Form.Control
name='pdate'
value={asset.pdate}
onChange={(e) => setAsset({...asset, pdate: e.targetvalue})}
/>
</Form.Group>
<Form.Group className="mb-3" >
<Form.Label>Status</Form.Label>
<Form.Control
name='status'
value={asset.status}
onChange={(e) => setAsset({...asset, status: e.targetvalue})}
/>
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</>
)
}
const ConnectedAssetForm = (props) => (
<AssetConsumer>
{ value => <AssetForm {...value} {...props} />}
</AssetConsumer>
)
export default ConnectedAssetForm;
Schema.rb
create_table "areas", force: :cascade do |t|
t.string "name"
t.string "address"
t.string "city"
t.string "country"
t.integer "zip"
t.string "mcontact"
t.string "pic"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "assets", force: :cascade do |t|
t.string "name"
t.string "description"
t.string "barcode"
t.decimal "price"
t.datetime "pdate"
t.string "status"
t.string "img"
t.bigint "area_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "category"
t.index ["area_id"], name: "index_assets_on_area_id"
end
enter image description here- Example of State being undefined while filling out the form
enter image description here- Example of network payload on form submit.
I have tried adding the :id to the assets model and controller but I still get the same error on my rails server.
I have also tried in the form doing the following for example
<Form.Group className="mb-3" >
<Form.Label>Asset Image</Form.Label>
<Form.Control
name='asset[img]'
value={asset.img}
onChange={(e) => setAsset({...asset, img: e.targetvalue})}
/>
</Form.Group>
but it still returns ActionController: :ParameterMissina (param is missing or the value is empty: asset) :
Thank you!