问题
I guess my API knowledge is still limited because I could not figure this out.
I have an app that sits on React front end and Rails backend. If I want to delete one item at a time, I can do something like this:
function deleteSomething(somethingId){
return fetch(`api/something/${somethingId}`, {
method: 'DELETE'
})
}
and in Rails controller, I do something like
def destroy
@something = Something.find(params[:id]).destroy
head :no_content
end
My routes look like this:
scope :api do
resources :something, only: [:index, :show, :create, :update, :destroy]
...
This time, I want to destroy multiple items at once. I found this SO post that talks about destroy_all; I tested it on my rails console and it worked like magic (isn't Rails itself magical?).
However, I could not figure out how to write fetch method or the routing.
def destroy
Something.destroy_all(:name => params[:name]) #if I want to destroy all Model with certain name
end
How can I write the fetch method? I don't think I should include every single ID and iterate one by one, because that goes against why I wanted to use destroy_all in the first place.
function deleteSomehing(name){
return fetch(`api/something/(what goes here?)`, {
method: 'DELETE'
})
}
Where should my fetch method be addressed/ routed to? What do I do with routing, should I create a new method inside controller for this, or can I stub it inside destroy?
EDIT:
Here is what I have tried, but it did not work (error: Uncaught (in promise) SyntaxError: Unexpected end of JSON input
)
function customDeleteName(name){
return fetch(`api/something/delete_by_name`, {
method: 'POST',
headers: {
'Content-Tye': 'application/json'
},
body: JSON.stringify({
name: name
})
}).then((response) => response.json())
}
Inside routes - api scope:
scope :api do
post '/something/delete_by_name' => 'something#delete_by_name'
Inside controller:
def delete_by_name
Something.destroy_all(:name => params[:name])
end
EDIT2:
#routes
scope :api do
delete `/something/delete_by_name/:name`, to: 'something#delete_by_name'
#controller
def delete_by_name
Something.destroy_all(:name => params[:name])
head :no_content
end
## JS side ##
#fetch:
function deleteSomething(name){
return fetch(`api/something/delete_by_name/${name}`, {
method: 'DELETE'
})
}
Error:
ActionController::RoutingError (No route matches [DELETE] "/api/something/delete_by_name/somename"):
回答1:
I think I would create a specific method/action for it on the controller. Given the model name, you can do:
"something".capitalize.constantize.destroy_all
If something
has 2 names you'll need to capitalize it correctly before calling constantize on it.
scope :api do
...
delete 'your/beautiful/route/:name', to: 'wherewild#thingsare'
wherewild_controller.rb
def thingsare
#do magic rails
end
Now, you'll have a problem if you choose the same route path as you're using for the current delete, so better choose another one.
回答2:
Figured out how to do it. @Micael's answer, although didn't solve it exactly, led me to the right direction. Big thanks to him!
I did a POST method onto the custom method/ route, and it worked:
#controller
def delete_by_name
Something.destroy_all(:name => params[:name])
head :no_content
end
#routes:
post '/delete_latest_name' => 'something#delete_by_name'
#JS#
function deleteSomething(name){
return fetch(`delete_latest_name`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: name
})
});
}
来源:https://stackoverflow.com/questions/45224342/how-to-send-fetch-request-to-perform-rails-destroy-all