Rails 4,Ajax 导致 404 和 500 错误
Posted
技术标签:
【中文标题】Rails 4,Ajax 导致 404 和 500 错误【英文标题】:Rails 4, Ajax causing a 404 and 500 error 【发布时间】:2016-02-22 05:19:54 【问题描述】:我正在关注 Michael Hartl 的 Rails 教程,Section 12.2.5,在完全按照他的教程进行操作后,我遇到了一个奇怪的 404/500 错误。
我对这个特定错误知之甚少,不知道如何修复它。
尝试从标准的关注和取消关注按钮切换到启用 Ajax 的关注/取消关注按钮时会发生错误。
关注按钮只会产生重复的 500 错误。 (见图)
单击“关注”按钮后,服务器控制台如下所示:
Started POST "/relationships" for ::1 at 2015-11-21 10:42:41 -0500
Processing by RelationshipsController#create as JS
Parameters: "utf8"=>"✓", "authenticity_token"=>"nUhePXUdztraIcRVmQ6ewMjzLBPLbCJKjvGUExoQu7XH+zTJYj9J/+wopP7kAI1ycAa5t0bG7fEuApgAQqcDDw==", "followed_id"=>"4", "commit"=>"Follow"
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 4]]
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "relationships" ("followed_id", "follower_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["followed_id", 4], ["follower_id", 1], ["created_at", "2015-11-21 15:42:41.359403"], ["updated_at", "2015-11-21 15:42:41.359403"]]
(3.4ms) commit transaction
Rendered users/_unfollow.html.erb (7.6ms)
Rendered relationships/create.js.erb (10.4ms)
Completed 500 Internal Server Error in 35ms (ActiveRecord: 4.6ms)
NoMethodError (undefined method `id' for nil:NilClass):
app/views/users/_unfollow.html.erb:1:in `_app_views_users__unfollow_html_erb__4478734189885612533_2206022220'
app/views/relationships/create.js.erb:1:in `_app_views_relationships_create_js_erb___3841425439351308004_2234925000'
app/controllers/relationships_controller.rb:8:in `create'
取消关注按钮在第一次点击时会产生 500 错误,然后再按一次 404 错误。 (见图)
单击取消关注按钮后,服务器控制台如下所示:
Started DELETE "/relationships/106" for ::1 at 2015-11-21 10:44:16 -0500
Processing by RelationshipsController#destroy as JS
Parameters: "utf8"=>"✓", "authenticity_token"=>"MQQWiFHmikzre6tgsaVNf25z1r4Ps4yMhiX6BVAHvWFrt3x8RsQNad1yy8vMq17N1oZDGoIZQzcm1vYWCLAF2w==", "commit"=>"Unfollow", "id"=>"106"
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
Relationship Load (0.2ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."id" = ? LIMIT 1 [["id", 106]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 4]]
Relationship Load (0.6ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? AND "relationships"."followed_id" = ? LIMIT 1 [["follower_id", 1], ["followed_id", 4]]
(0.4ms) begin transaction
SQL (1.3ms) DELETE FROM "relationships" WHERE "relationships"."id" = ? [["id", 106]]
(571.2ms) commit transaction
Rendered users/_follow.html.erb (7.3ms)
Rendered relationships/destroy.js.erb (10.0ms)
Completed 500 Internal Server Error in 608ms (ActiveRecord: 574.0ms)
NoMethodError (undefined method `id' for nil:NilClass):
app/views/users/_follow.html.erb:2:in `block in _app_views_users__follow_html_erb__4224173111585839618_2218160400'
app/views/users/_follow.html.erb:1:in `_app_views_users__follow_html_erb__4224173111585839618_2218160400'
app/views/relationships/destroy.js.erb:1:in `_app_views_relationships_destroy_js_erb___1536758446230344516_2256927580'
app/controllers/relationships_controller.rb:18:in `destroy'
在 Chrome 开发者工具中,显示触发错误的代码如下:
xhr.send( ( options.hasContent && options.data ) || null );
我将在下面将问题分为两部分...在添加启用 ajax 的按钮之前的工作原理以及开始产生错误的代码添加。
工作正常:标准按钮
这是在切换到 Ajax 之前的工作原理:
relationships_controller.rb
class RelationshipsController < ApplicationController
before_action :logged_in_user
def create
user = User.find(params[:followed_id])
current_user.follow(user)
redirect_to user
end
def destroy
user = Relationship.find(params[:id]).followed
current_user.unfollow(user)
redirect_to user
end
end
_follow.html.erb
<%= form_for(current_user.active_relationships.build) do |f| %>
<div><%= hidden_field_tag :followed_id, @user.id %></div>
<%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
_unfollow.html.erb
<%= form_for(current_user.active_relationships.find_by(followed_id: @user.id),
html: method: :delete ) do |f| %>
<%= f.submit "Unfollow", class: "btn" %>
<% end %>
所有测试都通过。 following_test.rb
require 'test_helper'
class FollowingTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
@other = users(:archer)
log_in_as(@user)
end
test "following page" do
get following_user_path(@user)
assert_not @user.following.empty?
assert_match @user.following.count.to_s, response.body
@user.following.each do |user|
assert_select "a[href=?]", user_path(user)
end
end
test "followers page" do
get followers_user_path(@user)
assert_not @user.followers.empty?
assert_match @user.followers.count.to_s, response.body
@user.followers.each do |user|
assert_select "a[href=?]", user_path(user)
end
end
test "should follow a user the standard way" do
assert_difference '@user.following.count', 1 do
post relationships_path, followed_id: @other.id
end
end
test "should follow a user with Ajax" do
assert_difference '@user.following.count', 1 do
xhr :post, relationships_path, followed_id: @other.id
end
end
test "should unfollow a user the standard way" do
@user.follow(@other)
relationship = @user.active_relationships.find_by(followed_id: @other.id)
assert_difference '@user.following.count', -1 do
delete relationship_path(relationship)
end
end
test "should unfollow a user with Ajax" do
@user.follow(@other)
relationship = @user.active_relationships.find_by(followed_id: @other.id)
assert_difference '@user.following.count', -1 do
xhr :delete, relationship_path(relationship)
end
end
end
不工作:AJAX 按钮
然后在教程的 Section 12.2.5 中,我们被告知像这样切换以下文件以启用 Ajax 关注/取消关注按钮:
_follow.html.erb
<%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
<div><%= hidden_field_tag :followed_id, @user.id %></div>
<%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
_unfollow.html.erb
<%= form_for(current_user.active_relationships.find_by(followed_id: @user.id),
html: method: :delete ,
remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn" %>
<% end %>
relationships_controller.rb
class RelationshipsController < ApplicationController
before_action :logged_in_user
def create
@user = User.find(params[:followed_id])
current_user.follow(@user)
respond_to do |format|
format.html redirect_to @user
format.js
end
end
def destroy
@user = Relationship.find(params[:id]).followed
current_user.unfollow(@user)
respond_to do |format|
format.html redirect_to @user
format.js
end
end
end
创建以下两个文件:
create.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>");
$("#followers").html('<%= @user.followers.count %>');
destroy.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>");
$("#followers").html('<%= @user.followers.count %>');
作者比说:
这样,您应该导航到用户个人资料页面并验证 您无需刷新页面即可关注和取消关注。
没有骰子。
运行bundle exec rake test
时出现4个测试错误:
ERROR["test_should_unfollow_a_user_with_Ajax", FollowingTest, 2015-11-13 14:40:53 -0500]
test_should_unfollow_a_user_with_Ajax#FollowingTest (1447443653.75s)
ActionView::Template::Error: ActionView::Template::Error: undefined method `id' for nil:NilClass
app/views/users/_follow.html.erb:2:in `block in _app_views_users__follow_html_erb___290914909715466310_2191384660'
app/views/users/_follow.html.erb:1:in `_app_views_users__follow_html_erb___290914909715466310_2191384660'
app/views/relationships/destroy.js.erb:1:in `_app_views_relationships_destroy_js_erb___2680666598962148369_2191775880'
app/controllers/relationships_controller.rb:18:in `destroy'
test/integration/following_test.rb:53:in `block (2 levels) in <class:FollowingTest>'
test/integration/following_test.rb:52:in `block in <class:FollowingTest>'
app/views/users/_follow.html.erb:2:in `block in _app_views_users__follow_html_erb___290914909715466310_2191384660'
app/views/users/_follow.html.erb:1:in `_app_views_users__follow_html_erb___290914909715466310_2191384660'
app/views/relationships/destroy.js.erb:1:in `_app_views_relationships_destroy_js_erb___2680666598962148369_2191775880'
app/controllers/relationships_controller.rb:18:in `destroy'
test/integration/following_test.rb:53:in `block (2 levels) in <class:FollowingTest>'
test/integration/following_test.rb:52:in `block in <class:FollowingTest>'
ERROR["test_should_follow_a_user_with_Ajax", FollowingTest, 2015-11-13 14:40:53 -0500]
test_should_follow_a_user_with_Ajax#FollowingTest (1447443653.81s)
ActionView::Template::Error: ActionView::Template::Error: undefined method `id' for nil:NilClass
app/views/users/_unfollow.html.erb:1:in `_app_views_users__unfollow_html_erb__1207823279820701916_2213161380'
app/views/relationships/create.js.erb:1:in `_app_views_relationships_create_js_erb__279097861293830543_2213276120'
app/controllers/relationships_controller.rb:8:in `create'
test/integration/following_test.rb:37:in `block (2 levels) in <class:FollowingTest>'
test/integration/following_test.rb:36:in `block in <class:FollowingTest>'
app/views/users/_unfollow.html.erb:1:in `_app_views_users__unfollow_html_erb__1207823279820701916_2213161380'
app/views/relationships/create.js.erb:1:in `_app_views_relationships_create_js_erb__279097861293830543_2213276120'
app/controllers/relationships_controller.rb:8:in `create'
test/integration/following_test.rb:37:in `block (2 levels) in <class:FollowingTest>'
test/integration/following_test.rb:36:in `block in <class:FollowingTest>'
ERROR["test_should_follow_a_user_the_standard_way", FollowingTest, 2015-11-13 14:40:53 -0500]
test_should_follow_a_user_the_standard_way#FollowingTest (1447443653.86s)
ActionController::ActionControllerError: ActionController::ActionControllerError: Cannot redirect to nil!
app/controllers/relationships_controller.rb:9:in `block (2 levels) in create'
app/controllers/relationships_controller.rb:8:in `create'
test/integration/following_test.rb:31:in `block (2 levels) in <class:FollowingTest>'
test/integration/following_test.rb:30:in `block in <class:FollowingTest>'
app/controllers/relationships_controller.rb:9:in `block (2 levels) in create'
app/controllers/relationships_controller.rb:8:in `create'
test/integration/following_test.rb:31:in `block (2 levels) in <class:FollowingTest>'
test/integration/following_test.rb:30:in `block in <class:FollowingTest>'
ERROR["test_should_unfollow_a_user_the_standard_way", FollowingTest, 2015-11-13 14:40:54 -0500]
test_should_unfollow_a_user_the_standard_way#FollowingTest (1447443654.06s)
ActionController::ActionControllerError: ActionController::ActionControllerError: Cannot redirect to nil!
app/controllers/relationships_controller.rb:19:in `block (2 levels) in destroy'
app/controllers/relationships_controller.rb:18:in `destroy'
test/integration/following_test.rb:45:in `block (2 levels) in <class:FollowingTest>'
test/integration/following_test.rb:44:in `block in <class:FollowingTest>'
app/controllers/relationships_controller.rb:19:in `block (2 levels) in destroy'
app/controllers/relationships_controller.rb:18:in `destroy'
test/integration/following_test.rb:45:in `block (2 levels) in <class:FollowingTest>'
test/integration/following_test.rb:44:in `block in <class:FollowingTest>'
76/76: [==================================] 100% Time: 00:00:10, Time: 00:00:10
Finished in 10.29205s
76 tests, 312 assertions, 0 failures, 4 errors, 0 skips
官方教程的github在这里:https://github.com/mhartl/sample_app_3rd_edition
【问题讨论】:
【参考方案1】:我有这个确切的问题。虽然您的 sn-ps 反映了这种变化,但对我来说,问题是 Hartl 没有对他在 relationships_controller.rb
中所做的关键更改之一进行 sn-p 突出显示(他确实在文本中谈到了它,我正在略读教程中的这一点)。
变化是user
从常规变量变为实例变量。所以:
user = User.find(params[:followed_id])
变成
@user = User.find(params[:followed_id])
添加该更改后,ActionView::Template::Error: undefined method 'id' for nil:NilClass
错误就解决了。
【讨论】:
以上是关于Rails 4,Ajax 导致 404 和 500 错误的主要内容,如果未能解决你的问题,请参考以下文章
AJAX、CORS、Chrome 和 HTTP 错误代码 (401,403,404,500) 的推荐解决方案
尝试访问损坏的图片 url 时抛出内部服务器错误 500 而不是 404