My app is using Rails for the API and React for the client. My attempts to create a resource are failing. I want to get one value (description) from the user and provide defaults for the rest.
Here's the server log:
Started POST "/api/v1/goals" for ::1 at 2020-09-21 07:05:13 -0700
Processing by Api::V1::GoalsController#create as HTML
Parameters: {"goal"=>{"description"=>"Leggo"}}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."uid" = $1 LIMIT $2 [["uid", "fake#email.com"], ["LIMIT", 1]]
Completed 500 Internal Server Error in 66ms (ActiveRecord: 0.6ms | Allocations: 14791)
RuntimeError (<ActionController::Parameters {"goal"=>{"description"=>"Leggo"}, "controller"=>"api/v1/goals", "action"=>"create"} permitted: false>):
app/controllers/api/v1/goals_controller.rb:52:in `goal_params'
app/controllers/api/v1/goals_controller.rb:19:in `create'
The controller action:
def create
#goal = Goal.new(goal_params, user_id: current_user.id, complete: false, category_id: 1)
if #goal.save
render json: #goal, status: :created, location: #goal
else
render json: #goal.errors, status: :unprocessable_entity
end
end
The strong params method:
def goal_params
raise params.inspect
params.fetch(:goal).permit(:description)
end
And the client-side request:
try {
await axios({
method: 'post',
url,
headers,
data: { goal: { description } }
});
console.log('Created goal');
setDescription('');
} catch (err) {
console.log(err);
}
Remove the raise params.inspect firstly.
If you're getting a 422 Unprocessable Entity response that means #goal.save isn't working - likely because of a validation requirement on your Goal model? Print #goal.errors in your console before you save it if you want to see exactly why.
Related
I have a rails 6 API (Backend) running a Vue & Flutter Frontend,
When I try to pass my user credentials to the API from Vue I am getting the following error:
app/controllers/signin_controller.rb:6:in `create'
Started POST "/signin" for ::1 at 2019-11-13 02:51:58 -0700
Processing by SigninController#create as HTML
Parameters: {"user"=>{"email"=>"xxxxxx#xxxxxx.co", "password"=>"[FILTERED]"}}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."email" IS NULL LIMIT $1 [["LIMIT", 1]]
↳ app/controllers/signin_controller.rb:5:in `create'
Completed 404 Not Found in 6ms (ActiveRecord: 2.1ms | Allocations: 3220)
ActiveRecord::RecordNotFound (Couldn't find User):
app/controllers/signin_controller.rb:5:in `create'
now I can go into my rails console and the User dose exist with the MATCHING email address.
I am not too sure what to do to get this user found and signed in.
I am using JWT Sessions to handle the tokens and axios to make the calls to the api.
here is my signin controller create action.
def create
user = User.find_by!(email: params[:email])
if user.authenticate(params[:password])
payload = { user_id: user.id }
session = JWTSessions::Session.new(payload: payload, refresh_by_access_allowed: true)
tokens = session.login
response.set_cookie(JWTSessions.access_cookie,
value: tokens[:access],
httponly: true,
secure: Rails.env.production?)
render json: { csrf: tokens[:csrf] }
else
not_authorized
end
end
and here is the full method I am sending from vue:
signin () {
let formData = new FormData()
formData.append('user[email]', this.user.email)
formData.append('user[password]', this.user.password)
this.$http.plain.post('/signin', formData, {emulateJSON: true})
.then(response => this.signinSuccessful(response))
.catch(error => this.signinFailed(error))
},
signinSuccessful (response) {
if (!response.data.csrf) {
this.signinFailed(response)
return
}
localStorage.csrf = response.data.csrf
localStorage.signedIn = true
this.$router.replace('/dashboard')
},
signinFailed (error) {
this.error = (error.response && error.response.data && error.response.data.error) || ''
delete localStorage.csrf
delete localStorage.signedIn
},
checkSignedIn () {
if (localStorage.signedIn) {
this.$router.replace('/dashboard')
}
}
}
Any assistance here would be greatly appreciated! Thanks in advance!
From the request log we can see that the parameters coming in to your controller are:
Parameters: {"user"=>{"email"=>"xxxxxx#xxxxxx.co", "password"=>"[FILTERED]"}}
We can also see query that is made to the database:
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."email" IS NULL LIMIT $1 [["LIMIT", 1]]
Especially
WHERE "users"."email" IS NULL
So the email you're passing into the query is nil.
You should find the user like this instead
User.find_by!(email: params[:user][:email])
Or preferably
def create
user = User.find_by!(email: user_params[:email])
...
end
def user_params
params.require(:user).permit(:email, :password)
end
I am new, so I apologize in advance if there is some issues with my explanation of my issue, I am using Ionic v1. on the frontend and this ruby tutorial for the backend: https://www.simplify.ba/articles/2016/06/18/creating-rails5-api-only-application-following-jsonapi-specification/.
I am trying to create a user and have that information stored in the backend, but continue to run into a 422 (Unprocessable Entity Error). I have read many different forums, but am stuck.
Here's my front end:
.controller('SignupCtrl', function($scope,SignupSession,$ionicPopup) {
$scope.signup = function(full_name, password, repeat_password) {
var user_session = new SignupSession({ user: { full_name: full_name, password: password }});
user_session.$save(
function(data){
window.localStorage['full_name'] = full_name;
window.localStorage['password'] = password;
$location.path('/app/playlists');
},
function(err){
$ionicPopup.alert({
title: 'An error occured',
template: err["data"]["error"]
});
}
);
}
})
.factory('SignupSession', function($resource) {
return $resource(window.server_url + "/users.json") //application/vnd.api+json
})
Here's my backend:
User Controller:
def create
user = User.new(user_params)
if user.save
render json: user, status: :created, meta: default_meta
else
render_error(user, :unprocessable_entity)
end
end
def user_params
ActiveModelSerializers::Deserialization.jsonapi_parse(params)
end
Sessions Controller:
def create
data = ActiveModelSerializers::Deserialization.jsonapi_parse(params)
Rails.logger.error params.to_yaml
user = User.where(full_name: data[:full_name]).first
head 406 and return unless user
if user.authenticate(data[:password])
user.regenerate_token
render json: user, status: :created, meta: default_meta,
serializer: ActiveModel::Serializer::SessionSerializer and return
end
Here's my log and info from Google Chrome:
Started POST "/users.json" for 127.0.0.1 at 2017-08-04 12:40:39 -0700
Processing by UsersController#create as JSON
Parameters: {"user"=>{"full_name"=>"btejes#yahoo.com", "password"=>"[FILTERED]"}}
[1m[35m (0.1ms)[0m [1m[36mbegin transaction[0m
[1m[35m (0.1ms)[0m [1m[31mrollback transaction[0m
[active_model_serializers] Rendered ActiveModel::Serializer::ErrorSerializer with ActiveModelSerializers::Adapter::JsonApi (0.29ms)
Completed 422 Unprocessable Entity in 6ms (Views: 0.7ms | ActiveRecord: 0.2ms)
{errors: [{source: {pointer: "/data/attributes/password"}, detail: "can't be blank"},…]}
errors
:
[{source: {pointer: "/data/attributes/password"}, detail: "can't be blank"},…]
Does it have something to do with the content type needing to have, "application/vnd.api+json" in the front end? Any help would be greatly appreciated, and I apologize in advance that this post is on the longer side.
Ben
I am doing an ajax request to rails passing in the data an id.
here is the ajax
function delete_availability(id) {
var id = id;
$.ajax({
type: "DELETE",
url: "/events/" + id,
statusCode: {
200: function() {
//alert("200");
},
202: function() {
//alert("202");
}
},
success: function(data) {
console.log('availability deleted');
},
error: function(xhr) {
alert("The error code is: " + xhr.statusText);
}
});
}
my destroy action
def destroy
#event = Event.find_by(params[:id]);
respond_to do |format|
if #event.destroy
format.json {
render json: {}
}
end
end
end
my event model has nothing in it
class Event < ActiveRecord::Base
end
the problem is even though rails receives correct id, when it goes for destroying, it changes id and destroys the next one.
here is the rails log:
Processing by EventsController#destroy as */*
Parameters: {"id"=>"66"}
Event Load (0.1ms) SELECT "events".* FROM "events" WHERE (66) LIMIT 1
(0.0ms) begin transaction
SQL (0.2ms) DELETE FROM "events" WHERE "events"."id" = ? [["id", 65]]
(2.4ms) commit transaction
Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 2.8ms)
anyone knows why?
You should use Event.find(params[:id]) or Event.find_by(id: params[:id]).
What happens with your code is that the SQL query finds every event - WHERE (66) is true for any record - and find_by takes the first record from the set, and it gets destroyed. The ID from the request doesn't matter.
Why you use find_by its used when you want to use with different attribute to search use:
Event.find(params[:id])
OR use find_by_id if you want to not throw an Exception if record not find
Event.find_by_id(params[:id])
OR if you still want to use find_by you can use which if no record is found it returns nil:
Event.find_by(id: params[:id])
and use find_by! to throuw an exception if no record found with this id:
Event.find_by!(id: params[:id])
In javascript I do an ajax call to the create function of deliveries_controller. This puts a new Delivery in the database with a product and quantity. I also try to put the current_user as user_id in the database, but for some reason it stays nil in the database.
My ajax call:
$.ajax({
type: "POST",
url: "/deliveries",
data: { delivery: {ingredient: "meel", quantity: "800", scenario_id: "3"} },
success: function(){
alert('Success!');
},
error: function(){
alert('No success');
}
});
I just pass some dummy data to test it all out.
and my deliveries_controller:
class DeliveriesController < ApplicationController
protect_from_forgery
def index
#storages = Storage.where(user_id: current_user)
end
def addQuantity
#storage = Storage.where(user_id: current_user.id)
#storage.update_all ("quantity = (quantity+200)")
redirect_to deliveries_url
end
def create
#delivery = Delivery.new(delivery_params)
respond_to do |format|
if #delivery.save
format.html do
render :nothing => true
end
format.json { render json: #delivery.to_json }
else
format.html { render :nothing => true} ## Specify the format in which you are rendering "new" page
format.json { render json: #delivery.errors } ## You might want to specify a json format as well
end
end
end
private
def delivery_params
params.require(:delivery).permit(:user_id, :ingredient, :quantity, :scenario_id)
end
end
New entries are created in the database, but whichever way I try to pass the user_id as param it isn't saved in the database.
I tried it like:
#delivery = Delivery.new(delivery_params, :user_id => current_user),
#user_id = current_user
#delivery = Delivery.new(delivery_params, #user_id)
and
params.require(:delivery).permit(:user_id, :ingredient, :quantity, :scenario_id).merge(user_id: current_user)
log:
Started POST "/deliveries" for 127.0.0.1 at 2014-11-03 12:59:37 +0100
Processing by DeliveriesController#create as */*
Parameters: {"delivery"=>{"ingredient"=>"meel", "quantity"=>"800", "scenario_id"=>"3"}}
Can't verify CSRF token authenticity
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'da39a3ee5e6b4b0d3255bfef95601890afd80709' LIMIT 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'da39a3ee5e6b4b0d3255bfef95601890afd80709' LIMIT 1
(0.0ms) begin transaction
SQL (0.2ms) INSERT INTO "deliveries" ("created_at", "ingredient", "quantity", "scenario_id", "updated_at") VALUES (?, ?, ?, ?, ?) [["created_at", "2014-11-03 11:59:37.253274"], ["ingredient", "meel"], ["quantity", 800], ["scenario_id", 3], ["updated_at", "2014-11-03 11:59:37.253274"]]
(12.5ms) commit transaction
Rendered text template (0.0ms)
Completed 200 OK in 24ms (Views: 0.8ms | ActiveRecord: 13.1ms)
but the user_id for Delivery stays nil. How would I pass the user_id from the current_user so it's saved in the database with the json I retrieve from the ajax call?
Thanks in advance
EDIT:
I fixed it the following way:
I send json data to javascript with content_tag:
= content_tag(:div,"", id: "storages", data:{url: Storage.where(user_id: current_user)})
this data is handled, and the user_id is suddenly accepted :)
thanks for the help!
Try this instead
#delivery = current_user.deliveries.new(delivery_params)
It should be
#delivery = Delivery.new(delivery_params.merge(user: current_user))
OR
#delivery = Delivery.new(delivery_params)
#delivery.user = current_user
Put current user_id on hidden field on HTML and send it with ajax like other params
I want use rails 4 as a server and post data to rails and then data is save to database. For this, I sen data by http and update method. But when data recieve in server and rails want to save data, I get Unpermitted parameters: id error. I post data by below code:
$scope.updateRadif = function(index, ID){
console.log(ID);
RadifSecure.update(index, {bolouk_id: 1, id: ID}).$promise.then(function(data){
//...
})
.catch(function (err) {
//...
})
};
app.factory('RadifSecure', function($resource) {
return $resource("/api/bolouks/:bolouk_id/radifs/:id", { bolouk_id: '#bolouk_id', id: "#id" },
{
'show': { method: 'GET', isArray: false },
'update': { method: 'PUT' },
'destroy': { method: 'DELETE' }
}
);
});
and I recieve data in rails server:
def update
#radif = Radif.find(params[:id])
respond_to do |format|
if #radif.update_attributes(radif_params)
format.json { head :no_content }
else
format.json { render json: #radif.errors, status: :unprocessable_entity }
end
end
end
private
def radif_params
params.require(:radif).permit(:bolouk_id, :describe, :price)
end
When I check the server log, the data is recieve ccorrectly, but rails doesn't permit to save in database:
Started PUT "/api/bolouks/1/radifs/16?describe=sdsad&price=3423432" for 127.0.0.1 at 2014-09-03 11:14:27 +0430
Processing by Api::V1::RadifsController#update as JSON
Parameters: {"bolouk_id"=>"1", "id"=>"16", "describe"=>"sdsad", "price"=>"3423432", "radif"=>{"id"=>"16", "bolouk_id"=>"1"}}
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 7 ORDER BY "users"."id" ASC LIMIT 1
Radif Load (0.0ms) SELECT "radifs".* FROM "radifs" WHERE "radifs"."id" = ? LIMIT 1 [["id", 16]]
Unpermitted parameters: id
(0.0ms) begin transaction
(0.0ms) commit transaction
Completed 204 No Content in 29ms (ActiveRecord: 0.0ms)
I try other code to solve this problem, but I'm not successful.
def update
#radif = Radif.find(params[:id])
radif.update!(radif_params)
end
Any one can help me to solve this problem?