Переход с Prototype на JQuery приводит к двойному POST
В главе 12 Руководства по Ruby on Rails Майкла Хартла на странице профиля пользователя есть кнопка, которую можно щелкнуть, чтобы подписаться или отписаться от него / нее. (См. Рисунки 12.12 и 12.13)
Я использую rvm 1.8.6 и Rails 3.1.1.
Когда я использую Prototype, поведение нажатия кнопки работает правильно. В /sample_app/app/views/layouts/application.html.erb,
<%= javascript_include_tag :defaults %>
При нажатии "следовать" сначала выполняется POST, а затем GET для повторного рендеринга страницы. Логи ниже.
Started POST "/relationships" for 127.0.0.1 at 2011-11-30 22:07:04 -0800
Processing by RelationshipsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"sVoNM/yyDmn0czvbza+dxzLsPW4mPNlGxAI1vKN7Ez4=", "relationship"=>{"followed_id"=>"13"}, "commit"=>"Follow"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", "13"]]
SQL (0.6ms) INSERT INTO "relationships" ("created_at", "followed_id", "follower_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Thu, 01 Dec 2011 06:07:04 UTC +00:00], ["followed_id", 13], ["follower_id", 1], ["updated_at", Thu, 01 Dec 2011 06:07:04 UTC +00:00]]
Redirected to ht.p://localhost:3000/users/13
Completed 302 Found in 52ms
Started GET "/users/13" for 127.0.0.1 at 2011-11-30 22:07:04 -0800
Processing by UsersController#show as HTML
Parameters: {"id"=>"13"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", "13"]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Relationship Load (0.2ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = 1 AND "relationships"."followed_id" = 13 LIMIT 1
CACHE (0.0ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = 1 AND "relationships"."followed_id" = 13 LIMIT 1
Rendered users/_unfollow.html.erb (6.9ms)
Rendered users/_follow_form.html.erb (54.5ms)
(0.2ms) SELECT COUNT(*) FROM "microposts" WHERE "microposts"."user_id" = 13
CACHE (0.0ms) SELECT COUNT(*) FROM "microposts" WHERE "microposts"."user_id" = 13
(0.2ms) SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = 13
(0.1ms) SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = 13
Rendered shared/_stats.html.erb (4.2ms)
Rendered users/show.html.erb within layouts/application (67.5ms)
Rendered layouts/_stylesheets.html.erb (1.4ms)
Rendered layouts/_header.html.erb (2.5ms)
Rendered layouts/_footer.html.erb (0.7ms)
Completed 200 OK in 100ms (Views: 83.1ms | ActiveRecord: 1.9ms)
Но после того, как я последовал главе 13 и переключился на JQuery, поведение нажатия кнопки "следовать" привело к исключению и сбоям веб-сервера. После того как я изменил /sample_app/app/views/layouts/application.html.erb на
<%= javascript_include_tag "application" %>
вместо этого это сделало бы POST дважды. И я думаю, уникальное нарушение БД разбило Рубин. Логи ниже.
Started POST "/relationships" for 127.0.0.1 at 2011-11-30 21:08:51 -0800
Processing by RelationshipsController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"sVoNM/yyDmn0czvbza+dxzLsPW4mPNlGxAI1vKN7Ez4=", "relationship"=>{"followed_id"=>"19"}, "commit"=>"Follow"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", "19"]]
SQL (4.6ms) INSERT INTO "relationships" ("created_at", "followed_id", "follower_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Thu, 01 Dec 2011 05:08:51 UTC +00:00], ["followed_id", 19], ["follower_id", 1], ["updated_at", Thu, 01 Dec 2011 05:08:51 UTC +00:00]]
Relationship Load (0.2ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = 1 AND "relationships"."followed_id" = 19 LIMIT 1
Rendered users/_unfollow.html.erb (3.7ms)
(0.2ms) SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = 19
Rendered relationships/create.js.erb (7.7ms)
Completed 200 OK in 103ms (Views: 13.7ms | ActiveRecord: 6.0ms)
Started POST "/relationships" for 127.0.0.1 at 2011-11-30 21:08:51 -0800
Processing by RelationshipsController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"sVoNM/yyDmn0czvbza+dxzLsPW4mPNlGxAI1vKN7Ez4=", "relationship"=>{"followed_id"=>"19"}, "commit"=>"Follow"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", "19"]]
SQL (0.5ms) INSERT INTO "relationships" ("created_at", "followed_id", "follower_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Thu, 01 Dec 2011 05:08:51 UTC +00:00], ["followed_id", 19], ["follower_id", 1], ["updated_at", Thu, 01 Dec 2011 05:08:51 UTC +00:00]]
SQLite3::ConstraintException: constraint failed: INSERT INTO "relationships" ("created_at", "followed_id", "follower_id", "updated_at") VALUES (?, ?, ?, ?)
Completed 500 Internal Server Error in 86ms
SQLite3::ConstraintException (columns follower_id, followed_id are not unique):
Rendered /home/anson/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-3.1.1/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.2ms)
Rendered /home/anson/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-3.1.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.0ms)
Rendered /home/anson/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-3.1.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (4.2ms)
/home/anson/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.1.1/lib/active_record/connection_adapters/sqlite_adapter.rb:84: [BUG] Segmentation fault
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]
-- control frame ----------
c:0044 p:---- s:0205 b:0205 l:000204 d:000204 CFUNC :close
...
[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
Aborted
Может кто-нибудь помочь, пожалуйста?
Коды ниже. приложение / просмотров / пользователей /_follow_form.html.erb
<% unless current_user?(@user) %>
<div id="follow_form">
<% if current_user.following?(@user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
приложение / просмотров / пользователей /_follow.html.erb
<%= form_for current_user.relationships.build(:followed_id => @user.id),
:remote => true do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<div class="actions"><%= f.submit "Follow" %></div>
<% end %>
приложение / просмотров / пользователей /_unfollow.html.erb
<%= form_for current_user.relationships.find_by_followed_id(@user),
:html => { :method => :delete },
:remote => true do |f| %>
<div class="actions"><%= f.submit "Unfollow" %></div>
<% end %>
приложение / контроллеры /relationships_controller.rb
class RelationshipsController < ApplicationController
before_filter :authenticate
def create
@user = User.find(params[:relationship][: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").update("<%= escape_javascript(render('users/unfollow')) %>")
$("followers").update('<%= "#{@user.followers.count} followers" %>')
приложение / просмотров / отношения /destroy.js.erb
$("follow_form").update("<%= escape_javascript(render('users/follow')) %>")
$("followers").update('<%= "#{@user.followers.count} followers" %>')
2 ответа
Проверьте вашу общую папку на наличие папки Assets, в которой находится application.js. Не уверен, как я закончил с этим, но это заставляло ajax-запросы обрабатываться дважды.
У меня была такая же проблема, в том числе сбои сервера, и мне удалось исправить это так: (запросы действительно были отправлены дважды, вероятно, из-за старых сценариев) - удалить практически все js-файлы, кроме application.js (который должен быть сгенерирован) по рельсам новый для рельсов 3.1)
# deleted: app/assets/javascripts/controls.js
# deleted: app/assets/javascripts/dragdrop.js
# deleted: app/assets/javascripts/effects.js
# deleted: app/assets/javascripts/prototype.js
# deleted: app/assets/javascripts/rails.js
Кроме того, create.js.erb необходимо адаптировать от прототипа к запросу:
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
$("#followers").html('<%= "#{@user.followers.count} followers" %>')
и так же, как destroy.js.erb:
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>")
$("#followers").html('<%= "#{@user.followers.count} followers" %>')
после этого все работало как раньше.