I'm trying to make a simple ajax request with Rails and Axios, but its seems that I have a routing problem
My Ajax request is make with POST method
axios.post('/post', {
title: title,
pseudo: pseudo,
text: text,
topic: topic
})
.then(res => console.log(res))
.catch(e => console.log(e))
}
My controller have respond_to
respond_to do |format|
format.json { render json: {result: 'ok'} }
end
But Rails processed with the wrong controller and the wrong method, I expected Processing by PostController#create as JSON not Processing by MainController#default as HTML
Started GET "/post?title=&text=++++++++++++&pseudo=" for 127.0.0.1 at 2021-03-16 12:29:23 +0100
Processing by MainController#default as HTML
Parameters: {"title"=>"", "text"=>" ", "pseudo"=>"", "topic"=>""}
Rendering main/default.html.erb within layouts/application
Post Load (1.4ms) SELECT "posts".* FROM "posts" WHERE (topic = '') ORDER BY "posts"."updated_at" DESC LIMIT $1 OFFSET $2 [["LIMIT", 12], ["OFFSET", 0]]
↳ app/views/main/default.html.erb:40
Rendered main/default.html.erb within layouts/application (Duration: 11.2ms | Allocations: 1178)
[Webpacker] Everything's up-to-date. Nothing to do
[Webpacker] Everything's up-to-date. Nothing to do
Completed 200 OK in 192ms (Views: 188.0ms | ActiveRecord: 1.4ms | Allocations: 11445)
Here my rails routes
Prefix Verb URI Pattern Controller#Action
GET / main#default
GET /:topic(.:format) main#default
comment_index POST /comment(.:format) comment#create
new_comment GET /comment/new(.:format) comment#new
comment GET /comment/:id(.:format) comment#show
post_index POST /post(.:format) post#create
new_post GET /post/new(.:format) post#new
GET /:topic/:post(.:format) post#show
Related
I have a strange problem with Devise that I was not able to figure out after several hours so I decided to bring it up to you to have a little help on the mater.
I have a tab panel which uses a turbo_frame_tag to render different tabs that have forms inside them. On form submission if they are errors it works perfectly, the turbo frame is rerendered with the form and its errors associated. However, on a successful form submission for the Devise form (here editing the user), it reloads the page but it does not render the content of the turbo frame whereas my rails server says it is rendering the appropriate html :sweat_smile:
I am giving you some code details below to help you understand:
– Where I display my tab content –
GET /settings (users#settings, users/settings.html.slim)
section { ... }
= render "shared/tab/navigation",
= turbo_frame_tag "tab_content", src: edit_user_registration_path
I put src: edit_user_registration_path because that it my first tab, it does not work with or without it.
I have a user edit form on my first tab, the issue is only for the Devise tab, for the other controllers/actions it works fine. Here for my user registration#edit (I curated the html for better understanding):
– The view I want to display in my turbo frame –
GET /settings/notifications (hairdressers#notifications_settings, hairdressers/notifications_settings.html.slim)
= turbo_frame_tag "tab_content"
section
= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put, class: "..." }) do |f|
# some inputs
= button_tag type: "submit",
class: "...",
data: { disable_with: "Submitting..." }
– The controller responsible for handling the request and displaying the view –
My Devise user#registrations controller:
class Users::RegistrationsController < Devise::RegistrationsController
# before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
layout "sign_in_up", except: %i[edit update]
# GET /resource/sign_up
# def new
# super
# end
# POST /resource
# def create
# super
# end
# GET /resource/edit
# def edit
# super
# end
# PUT /resource
# def update
# super
# end
# DELETE /resource
# def destroy
# super
# end
# GET /resource/cancel
# Forces the session data which is usually expired after sign
# in to be expired now. This is useful if the user wants to
# cancel oauth signing in/up in the middle of the process,
# removing all OAuth session data.
# def cancel
# super
# end
protected
# If you have extra params to permit, append them to the sanitizer.
# def configure_sign_up_params
# devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
# end
# If you have extra params to permit, append them to the sanitizer.
# def configure_account_update_params
# devise_parameter_sanitizer.permit(:account_update, keys: [:attribute])
# end
# The path used after sign up.
# def after_sign_up_path_for(resource)
# super(resource)
# end
# The path used after sign up for inactive accounts (ie not activated yet accounts)
# That's our 'after_sign_up_path_for' because we ask users to activate their
# account on sign up
def after_inactive_sign_up_path_for(resource)
users_welcome_path(resource_id: resource.id)
end
# CUSTOM: The path used after successful update.
def after_update_path_for(resource)
users_settings_path
end
end
So, when I successfully update my informations as a user with this form form, it redirects me properly to the /settings routes, however it does not display the content of my turbo_frame_tag (here registrations#edit) BUT my rails server says so …
Started PUT "/users" for ::1 at 2022-08-24 19:30:45 +0200
Processing by Users::RegistrationsController#update as TURBO_STREAM
Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"first_name"=>"Ulysse35", "last_name"=>"Benard1", "email"=>"mathieu#madeinvote.com", "phone_number"=>"06 59 86 98 64", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "current_password"=>"[FILTERED]"}}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
TRANSACTION (0.2ms) BEGIN
User Update (7.9ms) UPDATE "users" SET "updated_at" = $1, "first_name" = $2 WHERE "users"."id" = $3 [["updated_at", "2022-08-24 17:30:45.644398"], ["first_name", "Ulysse35"], ["id", 1]]
TRANSACTION (6.7ms) COMMIT
Redirected to http://localhost:3000/settings
Completed 302 Found in 397ms (ActiveRecord: 15.7ms | Allocations: 7481)
Started GET "/settings" for ::1 at 2022-08-24 19:30:45 +0200
Processing by UsersController#settings as TURBO_STREAM
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
↳ app/controllers/users_controller.rb:10:in `settings'
Rendering layout layouts/application.html.slim
Rendering users/settings.html.slim within layouts/application
Rendered shared/tab/_link_item.html.slim (Duration: 23.6ms | Allocations: 786)
Rendered shared/tab/_link_item.html.slim (Duration: 1.4ms | Allocations: 781)
Rendered shared/tab/_link_item.html.slim (Duration: 3.8ms | Allocations: 781)
Rendered shared/tab/_navigation.html.slim (Duration: 62.9ms | Allocations: 2577)
Rendered users/settings.html.slim within layouts/application (Duration: 66.0ms | Allocations: 2870)
Rendered shared/buttons/_flat_large_with_icon.html.slim (Duration: 1.1ms | Allocations: 773)
Rendered shared/buttons/_flat_large_with_icon.html.slim (Duration: 1.1ms | Allocations: 773)
Rendered shared/buttons/_flat_large_with_icon.html.slim (Duration: 1.0ms | Allocations: 773)
Rendered shared/buttons/_primary_compact_with_icon.html.slim (Duration: 2.4ms | Allocations: 772)
Rendered shared/buttons/_primary_large_with_icon.html.slim (Duration: 0.5ms | Allocations: 773)
Rendered shared/dropdown/_link_item.html.slim (Duration: 0.0ms | Allocations: 45)
Rendered shared/dropdown/_link_item.html.slim (Duration: 0.0ms | Allocations: 45)
Rendered shared/dropdown/_link_item.html.slim (Duration: 0.0ms | Allocations: 45)
Rendered shared/dropdown/_menu.html.slim (Duration: 0.3ms | Allocations: 363)
Rendered shared/_navbar.html.slim (Duration: 8.7ms | Allocations: 5647)
Rendered shared/_footer.html.slim (Duration: 1.1ms | Allocations: 21)
Rendered layout layouts/application.html.slim (Duration: 77.9ms | Allocations: 9322)
Completed 200 OK in 85ms (Views: 78.4ms | ActiveRecord: 0.2ms | Allocations: 10645)
Started GET "/users/edit" for ::1 at 2022-08-24 19:30:45 +0200
Processing by Users::RegistrationsController#edit as HTML
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Rendering layout layouts/application.html.slim
Rendering devise/registrations/edit.html.slim within layouts/application
Rendered devise/shared/_password_field.html.slim (Duration: 1.0ms | Allocations: 896)
Rendered devise/shared/_password_field.html.slim (Duration: 1.0ms | Allocations: 897)
Rendered devise/shared/_password_field.html.slim (Duration: 0.5ms | Allocations: 895)
Rendered shared/buttons/_submit_primary_large.html.slim (Duration: 1.7ms | Allocations: 779)
Rendered devise/registrations/edit.html.slim within layouts/application (Duration: 7.2ms | Allocations: 5268)
Rendered shared/buttons/_flat_large_with_icon.html.slim (Duration: 0.6ms | Allocations: 773)
Rendered shared/buttons/_flat_large_with_icon.html.slim (Duration: 2.0ms | Allocations: 773)
Rendered shared/buttons/_flat_large_with_icon.html.slim (Duration: 0.5ms | Allocations: 773)
Rendered shared/buttons/_primary_compact_with_icon.html.slim (Duration: 0.4ms | Allocations: 772)
Rendered shared/buttons/_primary_large_with_icon.html.slim (Duration: 2.0ms | Allocations: 773)
Rendered shared/dropdown/_link_item.html.slim (Duration: 0.0ms | Allocations: 45)
Rendered shared/dropdown/_link_item.html.slim (Duration: 0.0ms | Allocations: 45)
Rendered shared/dropdown/_link_item.html.slim (Duration: 0.0ms | Allocations: 45)
Rendered shared/dropdown/_menu.html.slim (Duration: 0.2ms | Allocations: 363)
Rendered shared/_navbar.html.slim (Duration: 6.5ms | Allocations: 5647)
Rendered shared/_footer.html.slim (Duration: 0.0ms | Allocations: 21)
Rendered layout layouts/application.html.slim (Duration: 14.2ms | Allocations: 11710)
Completed 200 OK in 17ms (Views: 14.6ms | ActiveRecord: 0.2ms | Allocations: 13505)
and it seems that I receive well the turbo_frame response, just that it is not inserted properly, but probably I am missing something here
Any suggestion to solve this issue would be appreciated, do not hesitate to ask for further information …
If anyone gets the same problem someday, here is a clean solution I found to make it work ;)
Just edit your registrations#edit and registrations#update actions with something like:
def edit
render turbo_stream: turbo_stream.replace("tab_content", partial: "devise/registrations/edit", locals: { resource: resource } )
end
Do not forget to transform your devise/views/registration/edit view into a _edit partial, anyway it is what it was in my case.
By making your edit action responding with a turbo_stream you will be assured that it gets replaced accordingly.
Only on Rails 6 when:
I receives a json response on pages with url like:
www.site.com/foo
and not when url is like:
www.site.com/foo?q=x
to reproduce:
rails new todo
rails scaffold Todo task:string
rails db:migrate
rails server
Create a task
In file show.json.jbuilder you'll see:
json.partial! "todos/todo", todo: #todo
Go to show page (todo/1)
Type on browser's console to se json response:
$.ajax({
url: window.location.href + ".json",
dataType: 'json',
async: false
});
When your url is "todo/1" jbuilder loads ok:
Started GET "/todos/1.json" for ::1 at 2019-10-28 13:55:54 -0300
Processing by TodosController#show as JSON
Parameters: {"id"=>"1"}
Todo Load (0.3ms) SELECT "todos".* FROM "todos" WHERE "todos"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/controllers/todos_controller.rb:67:in `set_todo'
Rendering todos/show.json.jbuilder
Rendered todos/_todo.json.jbuilder (Duration: 1.0ms | Allocations: 125)
Rendered todos/show.json.jbuilder (Duration: 2.2ms | Allocations: 306)
Completed 200 OK in 10ms (Views: 3.9ms | ActiveRecord: 0.3ms | Allocations: 1565)
But if your url is "todo/1?q=foo" you have no data:
Started GET "/todos/1?q=foo.json" for ::1 at 2019-10-28 13:55:44 -0300
Processing by TodosController#show as JSON
Parameters: {"q"=>"foo.json", "id"=>"1"}
Todo Load (0.2ms) SELECT "todos".* FROM "todos" WHERE "todos"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/controllers/todos_controller.rb:67:in `set_todo'
Rendering todos/show.html.erb within layouts/application
Rendered todos/show.html.erb within layouts/application (Duration: 0.7ms | Allocations: 89)
Completed 200 OK in 25ms (Views: 21.3ms | ActiveRecord: 0.2ms | Allocations: 6547)
Obs: I opened this rails github issue
In order to work in rails 6.0.0 we need to explicitly tell to use json format when the url has queries:
todos_controller.rb
change from:
def show
end
to:
def show
respond_to do |format|
format.html
format.json
end
end
This is because the request must be in the following form:
www.site.com/foo.json?q=x
If you want to pass parameters to the request, you can use the data parameter of ajax.
For instance:
$.ajax({
url: "/todos",
type: "GET",
data: {
id: 1,
q: "x"
},
success: function (response) {
console.log(response.data)
}
})
If I have a url like localhost:3000?id=2 what do I need to change to get my AJAX call to use the param?
page_controller.rb
class PageController < ApplicationController
def index
#pId = params[:id]
#p = Plant.where(id: #pId)
respond_to do |format|
format.json { render json: #p.to_json }
format.html
end
end
end
page.coffee
$ ->
$.ajax
dataType: 'json'
url: 'index.json'
success: (data) ->
alert "Data #{JSON.parse(data)} ---"
development.log for one page load
Processing by PageController#index as HTML
Parameters: {"id"=>"2"}
Rendering page/index.html.erb within layouts/application
[1m[36mPlant Load (1.0ms)[0m [1m[34mSELECT "plants".* FROM "plants" WHERE "plants"."id" = $1[0m [["id", 2]]
Rendered page/index.html.erb within layouts/application (3.0ms)
Completed 200 OK in 80ms (Views: 69.5ms | ActiveRecord: 1.0ms)
Started GET "/index.json" for ::1 at 2017-01-26 08:07:18 -0800
Processing by PageController#index as JSON
[1m[36mPlant Load (1.0ms)[0m [1m[34mSELECT "plants".* FROM "plants" WHERE "plants"."id" IS NULL[0m
Completed 200 OK in 5ms (Views: 0.1ms | ActiveRecord: 1.0ms)
This is just a very basic example taken from a much more complicated piece of code. Everything in my original code works except for when I'm trying to access to param.
update 1
routes.rb
Rails.application.routes.draw do
get 'index' => 'page#index'
root "page#index"
end
Your URI for the Ajax request doesn't include the parameter. You're making a call to index.json and not index.json?id=1
I'm unable to pass a variable to my controller using the data parameter of an AJAX call. What am I doing wrong?
show.html.erb
var parentStepID = 20;
$.ajax({
url: "/steps/create_branch",
type: 'GET',
data: {parent: parentStepID}
});
controller
def create_branch
parentStepID = params[:parent]
logger.debug("parentStepID: #{parentStepID}")
respond_to do |format|
format.js
end
end
The logger does not seem to get the parentStepID:
Started GET "/projects/20/steps/create_branch" for 127.0.0.1 at 2013-03-06 11:56:44 -0500
Processing by StepsController#create_branch as HTML
Parameters: {"project_id"=>"20"}
Project Load (0.1ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" = ? LIMIT 1 [["id", "20"]]
####################################################################
parentStepID:
Rendered steps/create_branch.js.erb (0.1ms)
Completed 200 OK in 16ms (Views: 10.6ms | ActiveRecord: 0.1ms)
Browser console:
20 0:412
/projects/20/steps/create_branch 0:413
Also, I believe the AJAX request is working properly; I created a file called "create_branch.js.erb"' in my steps views folder and put in an alert that is successfully called.
This is my route:
scope ":username" do
resources :feedbacks
end
So when I go to mydomain.com/test/feedbacks/10 it shows the correct feedback with id=10 that belongs to username=test.
But, if I go to mydomain.com/test2/feedbacks/10 it shows me the same feedback with id=10, which does NOT belong to username=test2.
How do I restrict this from happening?
I am using the Vanity gem to give me the username in the URL, this is what that route looks like:
controller :vanities do
match ':vname' => :show, :via => :get, :constraints => {:vname => /[A-Za-z0-9\-\+\#]+/}
end
Edit 1:
That is to say, for clarity's sake, when I go to mydomain.com/test/feedbacks/10 and /test2/feedbacks/10, it shows me the same view for the same record (in which case, the latter version would be wrong because it should be telling me that no such record exists, but it's not. It is just displaying the correct record for test/feedbacks/10).
Edit 2:
Here are the logs of both requests:
The right request
Started GET "/test-3/feedbacks/7" for 127.0.0.1 at 2011-09-14 02:48:15 -0500
Processing by FeedbacksController#show as HTML
Parameters: {"username"=>"test-3", "id"=>"7"}
Feedback Load (0.5ms) SELECT "feedbacks".* FROM "feedbacks" WHERE "feedbacks"."id" = ? LIMIT 1 [["id", "7"]]
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
Rendered feedbacks/show.html.erb within layouts/application (36.2ms)
Completed 200 OK in 188ms (Views: 184.3ms | ActiveRecord: 1.8ms)
The wrong request
Started GET "/test2/feedbacks/7" for 127.0.0.1 at 2011-09-14 02:48:28 -0500
Processing by FeedbacksController#show as HTML
Parameters: {"username"=>"test2", "id"=>"7"}
Feedback Load (0.1ms) SELECT "feedbacks".* FROM "feedbacks" WHERE "feedbacks"."id" = ? LIMIT 1 [["id", "7"]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
Rendered feedbacks/show.html.erb within layouts/application (37.6ms)
Completed 200 OK in 50ms (Views: 47.5ms | ActiveRecord: 1.2ms)
Your show action should look something like
def show
#user = User.find_by_username(params[:username])
if #user == current_user
...
render "show"
else
flash[:alert] = "Record doesn't exist"
redirect_to root_path
end
end
I took the liberty of adding in #Benoit's suggestion.