Ajaxがリロードしないと機能しない。
Railsチュートリアルにそって、Twitterライクなチャットアプリ開発の勉強をしております。フォロー機能を搭載し、ajaxをつけようとしているのですが、ページをリロードしないと表示が変わりません。followボタンを押すと、その場では何も変化がないような挙動をし、リロードすると、フォロー機能が実行され、画面にも変化が現れる状態です。
また、followボタンを2度以上押すと以下のようなエラーが発生します。
Completed 500 Internal Server Error in 6ms (ActiveRecord: 1.0ms)
ActiveRecord::RecordNotUnique (SQLite3::ConstraintException: UNIQUE constraint failed: relationships.follower_id, relationships.followed_id: INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)):
app/models/user.rb:77:in `follow'
app/controllers/relationships_controller.rb:6:in `create'
また、フォロー解除機能でも同様の挙動を示し、unfollowボタンを2度以上押すと以下のエラーが生じております。
Completed 404 Not Found in 2ms (ActiveRecord: 0.5ms)
ActiveRecord::RecordNotFound (Couldn't find Relationship with 'id'=128):
app/controllers/relationships_controller.rb:14:in `destroy'
これらのエラーは、データベース上ではボタン操作の1度目の処理で動作しているためだと考えられます。
Ajaxが上手く機能するには、どこを改善すれば良いでしょうか。
以下に、関連していると思われるコードと、該当するRailsチュートリアル記事のリンクを載せておきます。読みづらいコードかもしれませんが、どうかよろしくお願いいたします。
Railsチュートリアル:
https://railstutorial.jp/chapters/following_users?version=5.1#sec-a_working_follow_button_with_ajax
(app/controllers/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
(app/views/users/_follow_form.html.erb)
<% unless current_user?(@user) %>
<div class="follow_form">
<% if current_user.following?(@user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
(app/views/users/_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 %>
(app/views/users/_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 %>
(app/views/relationships/create.js.erb)
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>");
$("#followers").html('<%= @user.followers.count %>');
(app/views/relationships/destroy.js.erb)
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>");
$("#followers").html('<%= @user.followers.count %>');
(config/application.rb)
require_relative 'boot'
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module SampleApp
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.1
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# 認証トークンをremoteフォームに埋め込む
config.action_view.embed_authenticity_token_in_remote_forms = true
end
end
(追記)
RubyおよびRailsのバージョンは以下の通りです。
Ruby: 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin18]
Rails: 5.1.6