I am pretty new to programing so bare with me and I appreciate the help!
I have been stuck on this for a while but when I try to add a record from a form my rails server gives me ActionController::ParameterMissing (param is missing or the value is empty: asset).
Here is my controller for the assets-
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
render json: {errors: #asset.errors }, 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, :status, :img )
end
end
Here is the form-
import { useState } from 'react'
import {Form, Button} from 'react-bootstrap'
import {AssetConsumer} from '../../providers/AssetProvider'
const AssetForm = ({ setAdd, addAsset, areaId,}) => {
const [asset, setAsset] = useState ({ name: '', description: '', barcode: '', status: '', img: ''})
// const {areaId} = useParams
const handleSubmit = (e) => {
e.preventDefault()
addAsset(areaId, asset)
setAdd(false)
setAsset({ name: '', description: '', barcode: '', status: '', img: ''})
}
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})}
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>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;
Here is the Model-
class Asset < ApplicationRecord
belongs_to :area
validates :name, :description, :barcode,:img, presence: true
end
set the name attribute like this name='asset[name]'
<Form.Control
name='asset[name]'
value={asset.name}
onChange={(e) => setAsset({...asset, name: e.targetvalue})}
required
/>
Related
Currently im not able to update my obj becuz im getting a rails 422 unprocessible entity error .I have defined all the params properly not sure why this is happening pls take a look at my code below.I have a rails backend and react front end.
Routes.rb In my console I get a "EditReservationForm.js:14 PATCH http://localhost:4000/reservations/2 422 (Unprocessable Entity)" and in the rails logs
Started PATCH "/reservations/2" for 127.0.0.1 at 2022-09-01 11:53:07 +0530
Processing by ReservationsController#update as */*
Parameters: {"name"=>"koshieee", "date"=>"2022-08-30", "time"=>"2000-01-01T18:29:00.000Z", "num"=>2, "contact"=>12345, "occasion"=>"Bday", "id"=>"2", "reservation"=>{"name"=>"koshieee", "date"=>"2022-08-30", "time"=>"2000-01-01T18:29:00.000Z", "num"=>2, "contact"=>12345, "occasion"=>"Bday"}}
hello
4
Rails.application.routes.draw do
resources :reservations,only: [:index,:show,:create,:update,:destroy]
resources :reviews,only: [:index,:create,:destroy]
resources :restaurants,only: [:index]
post "/signup", to: "users#create"
get "/me", to: "users#show"
post "/login", to: "sessions#create"
delete "/logout", to: "sessions#destroy"
end
Reservation controller
class ReservationsController < ApplicationController
def index
reservations = #current_user.reservations
render json: reservations
end
def show
reservation = Reservation.find_by(id: params[:id])
if reservation
render json: reservation
else
render json: { error: "Reservation not found" }, status: :not_found
end
end
def create
reservation=Reservation.create!(reservation_params)
render json: reservation,status: :created
end
def update
reservation = Reservation.find_by(id: params[:id])
reservation.update!(reservation_params)
render json: reservation,status: :ok
end
def destroy
reservation = Reservation.find_by(id:params[:id])
if reservation
reservation.destroy
head :no_content
else
render json: {error: "Reservation Not Found ."}, status: :not_found
end
end
private
def reservation_params
params.permit(:name, :date, :time, :num, :contact, :occasion,:user_id,:restaurant_id)
end
end
EditForm.js
import { useState } from "react";
function EditReservationForm({reservation,onUpdateReservation}){
const{ name, date, time, num, contact, occasion}=reservation;
const[updateName,setUpdatedName]=useState(name);
const[updateDate,setUpdatedDate]=useState(date);
const[updateTime,setUpdatedTime]=useState(time);
const[updateNum,setUpdatedNum]=useState(num);
const[updateContact,setUpdatedContact]=useState(contact);
const[updateOccasion,setUpdatedOccasion]=useState(occasion);
function handleEditClick(e) {
e.preventDefault()
fetch(`/reservations/${reservation.id}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name:updateName,date:updateDate, time:updateTime,num:updateNum,contact:updateContact,occasion:updateOccasion}),
})
.then((r) => r.json())
.then((updatedReservation) => {
onUpdateReservation(updatedReservation);
});
}
return(
<>
<h2>Modify Reservation</h2>
<form onSubmit={handleEditClick} >
<div >
<label htmlFor="name" >Name</label>
<input type="text" name="name" value={updateName} onChange={(e) => setUpdatedName(e.target.value)} placeholder="name" />
</div>
<div >
<label htmlFor="date" >Date</label>
<input type="date" name="date" value={updateDate} onChange={(e) => setUpdatedDate(e.target.value)} placeholder="date" />
</div>
<div >
<label htmlFor="time" >Time</label>
<input type="time" name="time" value={updateTime} onChange={(e) => setUpdatedTime(e.target.value)} placeholder="time" />
</div>
<div >
<label htmlFor="num" >Num</label>
<input type="number" name="num" value={updateNum} onChange={(e) => setUpdatedNum(e.target.value)} placeholder="num" />
</div>
<div >
<label htmlFor="date" >Contact</label>
<input type="tel" name="contact" value={updateContact} onChange={(e) => setUpdatedContact(e.target.value)} placeholder="contact" />
</div>
<div >
<label htmlFor="occasion" >Occasion</label>
<input type="text" name="occasion" value={updateOccasion} onChange={(e) => setUpdatedOccasion(e.target.value)} placeholder="occasion" />
</div>
<button type="submit">Update Reservation</button>
</form>
</>
)
}
export default EditReservationForm;
```
Your strong parameters do not scope the nested params correctly. I guess it should be like this instead:
def reservation_params
params.require(:reservation)
.permit(:name, :date, :time, :num, :contact, :occasion, :user_id, :restaurant_id)
end
Note that there is no :user_id nor :restaureant_id in the parameters currently.
I am attempting to allow a user that is logged in to create a review for a game. I am having a couple issues that keep popping up in my console.
HTTP Origin header (http://localhost:3001) didn't match request.base_url (http://localhost:3000)
I attempted to remedy this with putting config.force_ssl = true in my production file from what I read up on, but still hitting this issue.
Im also hitting
NoMethodError (undefined method `id' for nil:NilClass):
which is ref my review_controller in create
app/controllers/reviews_controller.rb:19:in `create'
Below is my ReviewController and my ReviewContainer and ReviewForm
class ReviewsController < ApplicationController
# before_action :authorized, only:[:create]
before_action :authenticate_with_http_digest, only: [:new, :create]
def index
reviews = Review.all
render json: reviews
end
def show
review = Review.find_by(params[:id])
render json: review
end
def create
game = Game.find_or_create_by(name: params[:review][:game_name])
review = Review.new(review_params)
review.game_id = game.id
review.user_id = #user.id
review.save
render json: review
end
def update
review = Review.find(params[:id])
review.update(review_params)
review.save
render json: review
end
def destroy
review = Review.find(params[:id])
review.destroy
render json: {error: "Review Removed"}
end
private
def review_params
params.require(:review).permit(:user_id, :game_id, :user_username, :reviewed_game, :rating, :game_name)
end
end
import React, { Component } from 'react'
import Review from './Review'
import ReviewForm from './ReviewForm'
export default class ReviewsContainer extends Component {
state = {
reviews: [],
}
componentDidMount(){
fetch('http://localhost:3000/reviews')
.then(res => res.json())
.then(reviews => this.setState({ reviews }))
}
addReview = (review) => {
fetch('http://localhost:3000/reviews',{
method: "POST",
headers: {
"Content-Type" : "application/json",
Accept: "application/json",
Authorization: `bearer ${localStorage.token}`
},
body: JSON.stringify({ review: review }
),
})
.then(res => res.json())
.then(( json => {
this.setState(prevState => ({
reviews: [...prevState.reviews, json ]
}))
}))
}
// handleShowForm = () => {
// this.setState({edit: false})
// }
render() {
return (
<div className="review-grid">
<ReviewForm addReview={this.addReview} review={this.handleSubmit} />
<h1 className="review-content">REVIEWS!</h1>
<ul className="review-cards">
{
this.state.reviews.map(review => <Review key={review.id} review={review}/>)
}
</ul>
</div>
)
}
}
import React, { Component } from 'react'
class ReviewForm extends React.Component {
state = {
reviewed_game: '',
rating: '',
user_username: '',
}
handleReviewedGame = (event) => {
this.setState ({
reviewed_game: event.target.value
})
}
handleRating = (event) => {
this.setState ({
rating: event.target.value
})
}
handleUser = (event) => {
this.setState ({
user_username: event.target.value
})
}
handleForm = (e) => {
e.preventDefault()
// console.log(e)
const review = {
reviewed_game: this.state.reviewed_game,
rating: this.state.rating,
}
this.props.addReview(review)
}
render() {
return (
<div className="form-container">
<form onSubmit={(e) => {this.handleForm(e)}}>
<div>
<label>Review</label>
<br></br>
<textarea type="text" placeholder="Drop Your Review" rows={10} cols={50} value={this.state.reviewed_game} onChange={this.handleReviewedGame} className="form"/>
<div>
<label>Stars</label>
<br></br>
<input type="number" max="5" min="0" value={this.state.rating} onChange={this.handleRating} />
</div>
</div>
<button type="submit" className="sub-review">Create Review!</button>
</form>
</div>
)
}
}
export default ReviewForm;
Any advise on how to correct the issue is appreciated! thanks!
I am having an issue with submitting my data from form on the front end. Everytime I submit the form I get a Unpermitted parameter: :recipe
I was told to make sure my attributes on my frontend matched what was on the backend strong params.
Here is what is in my controller for my create action and my strong params
class RecipesController < ApplicationController
def create
recipe = Recipe.create(recipe_params)
if recipe.save
render json: recipe
else
render json: { error: "Couldn't save" }
end
end
private
def recipe_params
params.permit(:category_id,:name,:ingredients,:chef_name,:origin,category_attribute:[:category])
end
end
And here is my React frontend where I am inputting the info in the form
Side note I took out the event handlers for this code snippet but left the submit handler just to keep this explanation shorter
import React, { Component } from 'react'
import Categories from './Categories.js'
class RecipeInput extends Component{
constructor(props){
super(props)
this.state = {
category: [],
categoryId: '',
name:'',
ingredients: '',
chef_name: '',
origin: ''
}
this.handleNameChange.bind(this)
this.handleOriginChange.bind(this)
this.handleChefChange.bind(this)
this.handleIngChange.bind(this)
}
componentDidMount(){
let initialCats = [];
const BASE_URL = `http://localhost:10524`
const CATEGOREIS_URL =`${BASE_URL}/categories`
fetch(CATEGOREIS_URL)
.then(resp => resp.json())
.then(data => {
initialCats = data.map((category) => {
return category
})
console.log(initialCats)
this.setState({
category: initialCats,
})
});
}
handleSubmit = (event) =>{
event.preventDefault();
this.props.postRecipes(this.state)
this.setState({
categoryId: '',
name:'',
ingredients: '',
chef_name: '',
origin: ''
})
}
render(){
return(
<div>
<form onSubmit={this.handleSubmit}>
<Categories category={this.state.category}/>
<div>
<label for='name'>Recipe Name:</label>
<input type='text' value={this.state.name} onChange={this.handleNameChange} />
</div>
<div>
<label for='name'>Country Origin:</label>
<input type='text' value={this.state.origin} onChange={this.handleOriginChange} />
</div>
<div>
<label for='name'>Chef Name:</label>
<input type='text' value={this.state.chef_name} onChange={this.handleChefChange} />
</div>
<div>
<label for='name'>Ingredients:</label>
<textarea value={this.state.ingredients} onChange={this.handleIngChange} />
</div>
<input value='submit' type='submit'/>
</form>
</div>
)
}
}
export default RecipeInput
I am just a little clueless on where to go to from here. Am I matching the attributes correctly?
Edit
I forgot to include my postRecipes function with my dispatches in place
export const postRecipes = (recipe)=>{
const BASE_URL = `http://localhost:10524`
const RECIPES_URL =`${BASE_URL}/recipes`
const config = {
method: "POST",
body:JSON.stringify(recipe),
headers: {
"Accept": "application/json",
"Content-type": "application/json"
}
}
//category field
return(dispatch)=>{
fetch(RECIPES_URL,config)
.then(response =>
response.json())
.then(resp => {
dispatch({
type: 'Add_Recipe',
payload:{
category:resp.category,
name: resp.name,
ingredients: resp.ingredients,
chef_name: resp.chef_name,
origin: resp.origin,
categoryId: resp.categoryId
}
})
})
//.then(response => <Recipe />)
.catch((error) => console.log.error(error))
}
}
Edit
Here is my reducer that defines my Add-Recipe action for payload.
export default function manageRecipes(state={
recipes:[],
category:[],
}, action){
switch(action.type){
case 'Add_Recipe':
const recipe = {
name: action.name,
ingredients: action.ingredients,
chef_name: action.chef_name,
origin: action.origin,
categoryId: action.categoryId,
category: action.category,
// id: cuidFn()
}
return{
...state,
recipes: [...state.recipes, recipe],
}
case 'Delete_Recipe':
const recipes = state.recipes.filter(recipe => recipe.id !== action.id)
return {...state, recipes}
case 'Add_Catagory':
const cat = {
name: action.name
}
return{
...state,
category: [...state.category, cat],
}
default:
return state
}
}
try this in your backend
def recipe_params
params.require(:recipe).permit(
:category_id, :name,:ingredients, :chef_name,
:origin,category_attribute:[:category]
)
end
EDIT:
bwalshy - helped me solve the issue - I was rendering a static error message, instead of the actual server response. Once I rendered the server response it was obvious that I was trying to create the test account with the password as "123" which is too weak for the gem's standards. Coding is a humbling experience.
I've seen this question posted, but without any solutions that work for me. I have a React front end that is mounted on top of a Rails app. When I try to call my registrations controller I am getting the following error:
Completed 422 Unprocessable Entity in 103ms
I saw this this could be token related, and logging the token shows what appears to be a valid one: v4Ml1tlzkgBKWBcYGP9SGO+YVL7fxcxs3D8MhC3Z/3ZcZOa5rYGSHUABG+vL+yJfoVfO1Ks6RLI60sQDk7Hh8A==
which is being passed in the headers
The server response is:
{"error":"signup error"}
Here is the React component
import React from "react";
class SignUp extends React.Component {
constructor(props) {
super(props);
this.state = {
signupUnsuccessful: false,
email: '',
passwordOne: '',
passwordTwo: '',
error: null,
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
};
onChange = event => {
this.setState({ [event.target.name]: event.target.value });
}
//this is erroring and I think it's because I'm not telling devise to deliver json
onSubmit(event) {
event.preventDefault();
const url = "http://localhost:3000/users";
const { email } = this.state;
const password = this.state.passwordOne
const userInfo = {
user: {
email,
password
}
}
const token = document.querySelector('meta[name="csrf-token"]').content;
console.log(token)
fetch(url, {
method: "POST",
headers: {
"X-CSRF-Token": token,
"Content-Type": "application/json"
},
body: JSON.stringify(userInfo)
})
.then(response => {
if (response.ok) {
return response.json();
}
throw new Error("Network response was not ok.");
})
.catch(error => console.log(error.message));
}
render() {
const {
email,
passwordOne,
passwordTwo,
error,
} = this.state;
const isInvalid =
passwordOne !== passwordTwo ||
passwordOne === '' ||
email === '';
return (
<div>
<h2>Signup</h2>
<form onSubmit={this.onSubmit}>
<input name="email"
value={email}
onChange={this.onChange}
type="text"
placeholder="Email Address"/>
<input name="passwordOne"
value={passwordOne}
onChange={this.onChange}
type="password"
placeholder="Password" />
<input name="passwordTwo"
value={passwordTwo}
onChange={this.onChange}
type="password"
placeholder="Confirm Password"/>
<button disabled={isInvalid} type="submit">
Sign Up
</button>
</form>
<button onClick={() => this.props.changePage("login")}>Login!</button>
</div>
);
};
};
export default SignUp;
and the controller:
class RegistrationsController < Devise::RegistrationsController
def create
#user = User.new(user_params)
if #user.save
render json: #user
else
warden.custom_failure!
render json: { error: 'signup error' }, status: :unprocessable_entity
end
end
def update
#user = User.find_by_email(user_params[:email])
if #user.update_attributes(user_params)
render json: #user
else
warden.custom_failure!
render :json=> #user.errors, :status=>422
end
end
def destroy
#user = User.find_by_email(user_params[:email])
if #user.destroy
render :json=> { success: 'user was successfully deleted' }, :status=>201
else
render :json=> { error: 'user could not be deleted' }, :status=>422
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
And my routes
Rails.application.routes.draw do
devise_for :users, controllers: { registrations: 'registrations', sessions: 'sessions' }
root 'homepage#index'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
I'm trying to upload images to a rails 5 api app with carrierwave and react but for some reason it doesn't work.
Here're some parts of the app.
migration
class AddImagesToTopics < ActiveRecord::Migration[5.1]
def change
add_column :topics, :images, :json
end
end
topic model
class Topic < ApplicationRecord
mount_uploader :images, ImageUploader
...
end
topics controller
def topic_params
params.require(:topic).permit(:name, :options, :subject, :body, {images: []})
end
submitted form logs
#topic = #board.topics.new(topic_params)
p "-----------"
p params[:topic][:images]
p #topic
p "-----------"
gives the following:
Unpermitted parameter: :images
"-----------"
<ActionController::Parameters {"0"=>{}} permitted: false>
#<Topic id: nil, board_id: 5, body: "dsf", created_at: nil, updated_at: nil, name: "", options: "", subject: "", images: nil>
"-----------"
form
class Form extends Component {
constructor(props) {
super(props)
this.state = {
topic: {
name: "",
options: "",
subject: "",
body: "",
images: null
}
}
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
this.handleImagesSelect = this.handleImagesSelect.bind(this)
}
handleSubmit(e) {
e.preventDefault();
this.props.add_topic(this.props.perm, this.state);
}
handleChange(e) {
this.setState({ topic: { ...this.state.topic, [e.target.name]: e.target.value } });
}
handleImagesSelect(e) {
this.setState({ topic: { ...this.state.topic, images: e.target.files } });
console.log(e.target.files);
console.log(this.state);
}
render() {
const { name, options, subject, body, images } = this.state.topic
return(
<div>
<div className="form_wrapper">
<form id="form" onSubmit={this.handleSubmit } encType="multipart/form-data">
<table>
<tbody>
....
<tr>
<td>body</td>
<td>
<textarea name="body" id="body" rows="10" cols="50"
value={body}
onChange={this.handleChange}/>
</td>
</tr>
<tr>
<td>file</td>
<td>
<input name="images" type="file" id="images" multiple="true"
onChange={this.handleImagesSelect}/>
</td>
</tr>
</tbody>
</table>
</form>
</div>
<hr/>
</div>
)
}
}
add topic action
export function add_topic(perm, topic) {
return dispatch => {
axios.post(api + perm + "/topics/", topic)
.then((res) => {
dispatch({ type: ADD_TOPIC, payload: res.data })
})
.catch((err) => console.log(err))
}
}