前提・実現したいこと
■最終的な目的:Railsアプリでajax処理での「いいね機能」実装
■アプリ概要:口コミサイトアプリで、店舗リソース、ユーザーリソース(Devise利用)、コメントリソース、いいねリソースの4つで動かしています。
■いいね機能概要:店舗詳細ページに、いいねボタンを配置し、押下することで「いいねリソース」にデータが入るという仕組みです。
現在、Qiitaの参考記事 をもとに、コードを書いてみているのですが、どうしても狙い通りに動かず困っています。
以下に記事と同じ順ににコードを転記していくので、お力を貸して頂けるようお願いします。
参考記事:【Rails】いいね機能の実装(.js.erbを用いない方法)【プログラミング学習165日目】
発生している問題・エラーメッセージ
①ローカル環境でも本番環境でも、ページ自体は開け、「いいね!(adminでいいねリソースにデータを入れると、いいね!を取り消す)」も表示されるのですが、実際に押下してみると、「いいね!に失敗しました」とエラーメッセージが表示されます。
②「いいね!(adminでいいねリソースにデータを入れると、いいね!を取り消す)」部分がテキストのままで、記事のようにボタンデザインが導入されません。
唯一、記事と異なるポイントとしては、app/assets/javascripts/application.jsで、「//= require popper」の記述を省いていることです。
理由としては、この記述を追加すると、ページにアクセスする時点でエラーが表示されるようになり、調べてみても、bootstrapやsassのことばかりが出てくる為、おそらく環境の相違によるもので、自分の場合には必要ではないのでは?と考えたからです。
試したこと
Gemfile
1source 'https://rubygems.org' 2 3git_source(:github) do |repo_name| 4 repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") 5 "https://github.com/#{repo_name}.git" 6end 7 8 9# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 10gem 'rails', '5.1.6' 11gem 'devise' 12gem 'cancancan' 13gem 'rails_admin', '~> 1.3' 14gem 'carrierwave', '1.2.2' 15gem 'mini_magick', '4.7.0' 16gem 'bootstrap-sass', '3.3.7' 17gem 'puma', '3.9.1' 18gem 'sassc-rails' 19gem 'uglifier', '3.2.0' 20gem 'coffee-rails', '4.2.2' 21gem 'coffee-script-source', '1.8.0' 22gem 'jquery-rails', '4.3.1' 23gem 'turbolinks', '5.0.1' 24gem 'jbuilder', '2.7.0' 25 26 27group :development, :test do 28 # Call 'byebug' anywhere in the code to stop execution and get a debugger console 29 gem 'sqlite3', '1.3.13' 30 gem 'byebug', '9.0.6', platforms: [:mri, :mingw, :x64_mingw] 31 # Adds support for Capybara system testing and selenium driver 32end 33 34group :development do 35 # Access an IRB console on exception pages or by using <%= console %> anywhere in the code. 36 gem 'web-console', '3.5.1' 37 gem 'listen', '3.1.5' 38 gem 'spring', '2.0.2' 39 gem 'spring-watcher-listen', '2.0.1' 40end 41 42group :test do 43 gem 'rails-controller-testing', '1.0.2' 44 gem 'minitest', '5.10.3' 45 gem 'minitest-reporters', '1.1.14' 46end 47 48group :production do 49 gem 'pg', '0.20.0' 50 gem 'fog', '1.42' 51end 52 53# Windows does not include zoneinfo files, so bundle the tzinfo-data gem 54gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
app/assets/javascripts/application.js
//= require jquery3 //= require rails-ujs //= require turbolinks //= require bootstrap-sprockets //= require_tree .
app/models/like.rb
class Like < ApplicationRecord belongs_to :user belongs_to :bookshop end
db/migrate/[timestamp]_create_likes.rb
class CreateLikes < ActiveRecord::Migration[5.1] def change create_table :likes do |t| t.references :bookshop, foreign_key: true t.references :user, foreign_key: true t.timestamps end add_index :likes, [:user_id, :bookshop_id], unique: true end end
app/models/user.rb
class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable has_many :comments, dependent: :destroy has_many :bookshop, through: :comments has_many :likes, dependent: :destroy has_many :like_bookshops, through: :likes, source: :bookshop end
app/models/bookshop.rb
class Bookshop < ApplicationRecord mount_uploader :image_data, PictureUploader has_many :comments, dependent: :destroy has_many :users, through: :comments has_many :likes, dependent: :destroy has_many :like_users, through: :likes, source: :user validates :name, presence: true, length: {maximum: 50} validates :phone, presence: true, uniqueness: true validates :address, presence: true, length: {maximum: 100} validates :area, presence: true, length: {maximum: 20} validates :station, presence: true, length: {maximum: 20} # アップロードされた画像のサイズを最大5MBにバリデーションする def picture_size if picture.size > 5.megabytes errors.add(:picture, "should be less than 5MB") end end def like?(user) like_users.include?(user) end end
routes.rb
resources :bookshops do resources :comments, only: [:create] resources :likes, only: [:create] end end
app/controllers/likes_controller.rb
def create @bookshop = Bookshop.find(params[:bookshop_id]) @like = current_user.likes.find_by(bookshop: @bookshop) toggle end private def toggle if @like return head :unprocessable_entity unless @like.destroy else @like = current_user.likes.build(bookshop: @bookshop) return head :unprocessable_entity unless @like.save end head :ok end
app/views/likes/_like.html.erb
<% if user_signed_in? unless @bookshop.like?(current_user) %> <a class="btn-primary" data-bookshop_id="<%= ::Temple::Utils.escape_html_safe((@bookshop.id)) %>" id="link-mark">いいね!</a> <% else %> <a class="btn-secondary" data-bookshop_id="<%= ::Temple::Utils.escape_html_safe((@bookshop.id)) %>" id="link-mark">いいね!を取り消す</a> <% end; end %> <%= ::Temple::Utils.escape_html_safe((javascript_include_tag('like'))) %>
app/models/bookshop.rb
has_many :likes, dependent: :destroy has_many :like_users, through: :likes, source: :user def like?(user) like_users.include?(user) end
app/assets/javascripts/like.js
$(function(){ // id="link-mark"の箇所(いいねボタン)をクリックしたら $('#link-mark').on('click', function(){ // 非同期でlikes#createに処理を送信+その時に店舗情報(bookshop_id)を渡す $.ajax({ url: '/likes', type: 'POST', data: {bookshop_id: $(this).data('bookshop_id')} }) // 処理が上手く行ったらボタンを切り替えて .done((data) => { if ($(this).text() === 'いいね!') { $(this).text('いいね!を取り消す').removeClass('btn-primary').addClass('btn-secondary'); } else if ($(this).text() === 'いいね!を取り消す') { $(this).text('いいね!').removeClass('btn-secondary').addClass('btn-primary'); } }) // 処理が上手く行かなかったら失敗の旨を伝えるアラートを表示 .fail((data) => { alert('いいね!に失敗しました'); }) }); });
補足情報(FW/ツールのバージョンなど)
ruby 2.4.5
Rails 5.1.6
以上になります。
不足情報等あればすぐに追記しますので、よろしくお願いします。
回答1件
あなたの回答
tips
プレビュー