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])
Related
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.
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
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?
I have a link
%a{href: "#", :data => {verifying_link: 'yes', id: link.id, table_row: index}}
verify_by_js
that calls
$(function(){
$("a[data-verifying-link]='yes'").click(function(){
// spinner here
a=$(this).parent()
a.html('-spinner-')
var id= $(this).data("id");
var row = $(this).data("tableRow");
$.get("/verify_link/"+id+"&table_row="+row, function(data) {
if (data.link.verified_date !== undefined) {
$("span#verify_link_"+row).html('<span class="done">Verified</span>');
} else {
$("span#verify_link_"+row).html('<span class="undone">Unverified</span>');
}
});
//a.html('DONE')
});
});
It does get called, I see the -spinner- text but then I always get 'Unverified' in the ui, even though the record was verified (verified date set) in the datbase. If I actually refresh the browser page however I see the verified date which shows that the update was actually successful.
The controller code is:
def verify_link
#link = Link.find(params[:id])
if #link.valid_get?
#link.update_attribute(:verified_date, Time.now)
end
end
The network tab is showing a valid get for /verify_link/377&table_row=0
The piece I feel I am not getting is how function(data) {
if (data.link.verified_date !== undefined works (it was recommended from another question-answer and how that is used by the get call.
Server log shows:
Started GET "/verify_link/377&table_row=0" for 127.0.0.1 at 2014-08-03 21:52:06 -0400
Processing by LinksController#verify_link as */*
Parameters: {"id"=>"377&table_row=0"}
User Load (0.2ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
Link Load (0.4ms) SELECT `links`.* FROM `links` WHERE `links`.`id` = 377 LIMIT 1
(0.1ms) BEGIN
(0.4ms) UPDATE `links` SET `verified_date` = '2014-08-04 01:52:06', `updated_at` = '2014-08-04 01:52:06' WHERE `links`.`id` = 377
(0.5ms) SELECT COUNT(*) FROM `links` WHERE (1 = 1 AND position = 347)
(44.6ms) COMMIT
Rendered links/verify_link.js.erb (0.2ms)
Completed 200 OK in 347.0ms (Views: 5.3ms | ActiveRecord: 46.3ms)
which is a little confusing as it references app/view/links/verify_link.js.erb but this isn't what is used as it has
$ cat app/views/links/verify_link.js.erb
<%- if #link.verified_date %>
$("span#verify_link_<%=params['table_row']%>").html('<span class="done">Verified</span>');
<%- else %>
$("span#verify_link_<%=params['table_row']%>").html('<span class="undone">Unverified</span>');
<%- end %>
and that has the text Verified or Unverified whereas I made the previous one have different text - Verified OK and Not Verified to make sure and it is those being used in the ui and it is ("Not verified").
do this thing in your controller. As i dont see any proper return value on success and error.
def verify_link
#link = Link.find(params[:id])
if #link.valid_get?
if #link.update_attribute(:verified_date, Time.now)
render nothing: true, status: 200
else
render nothing: true , status: 422
end
end
end
Do this to the desire javascript file. And change $.get to $.ajax since $.get callback is only called when the request was successful not on failier. Indirectly it also means that, since the DOM is updating (its okay incorrectly) due to the $.get callback it means that the request is successful. I am using $.ajax as it looks more elegant.
$(function(){
$("a[data-verifying-link]='yes'").click(function(){
// spinner here
a=$(this).parent()
a.html('-spinner-')
var id= $(this).data("id");
var row = $(this).data("tableRow");
$.ajax({
url: "/verify_link/"+id+"&table_row="+row ,
type: 'GET',
success: function(r) {
$("span#verify_link_"+row).html('<span class="done">Verified</span>');
},
error: function(r) {
$("span#verify_link_"+row).html('<span class="undone">Unverified</span>');
},
complete: function(r) {
a.html('DONE');
}
});
});
});