牌語備忘録 -pygo

あくまでもメモです。なるべくオフィシャルの情報を参照してください。

牌語備忘録 -pygo

Rails4 でお気に入りをオン・オフするトグルボタンみたいのをやってみるメモ

(rails4.1.1, ruby2.1.1)

プロジェクト作成とか

$ rails new favorite_button_sample -T 
$ cd favorite_button_sample

ボタン表示を分りやすくするのに CDN の bootstrap 使ってみた
app/views/layouts/application.html.erb

  <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
  <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>

ユーザモデル生成

$ rails generate model user name
$ rake db:migrate
# app/models/user.rb

class User < ActiveRecord::Base
  has_many :comments
  has_many :favorites
end
動作確認用ダミー current_user 作成

認証機能つくるの面倒だったので。サンプルだし。

$ rails c
> User.create(name: "foo")
# app/controllers/application_controller.rb

  helper_method :current_user

  private
  def current_user
    # dummy user
    User.find_or_create_by(id: 1, name: "booboo")
  end

コメントのスキャフォールド生成

$ rails generate scaffold comment content:text user:references
$ rake db:migrate
$ rails c
> Comment.create(content: "foo bar baz", user_id: User.first)
# app/models/comment.rb
class Comment < ActiveRecord::Base
  belongs_to :user
  has_many :favorites

  def favorite_for(user)
    favorites.find_by(user_id: user)
  end
end

app/views/comments/index.html.erb

<h1>Listing comments</h1>

<table>
  <tbody id="comments">
    <% @comments.each do |comment| %>
      <tr>
        <td><%= comment.content %></td>
        <td id="comment_<%= comment.id %>">
          <%= render 'favorites/favorite_button', comment: comment, favorite: comment.favorite_for(current_user) %>
        </td>
        <td><%= link_to 'Show', comment %></td>
        <td><%= link_to 'Edit', edit_comment_path(comment) %></td>
        <td><%= link_to 'Destroy', comment, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Comment', new_comment_path %>

お気に入りモデル生成

rails generate model favorite user:references comment:references
# db/migrate/20140617045748_create_favorites.rb
class CreateFavorites < ActiveRecord::Migration
  def change
    create_table :favorites do |t|
      t.references :user, index: true
      t.references :comment, index: true

      t.timestamps
    end
    add_index :favorites, [:user_id, :comment_id], unique: true
  end
end
# config/routes.rb

  resources :favorites, only: [:create, :destroy]
# app/models/favorite.rb

class Favorite < ActiveRecord::Base
  belongs_to :user
  belongs_to :comment
end
# app/views/favorites/_favorite_button.html.erb
<% if comment.favorite_for current_user %>
  <%= link_to "Favorite", favorite_path(favorite), method: :delete, remote: true, class: 'btn btn-xs btn-warning' %>
<% else %>
  <%= link_to "Favorite", favorites_path(comment_id: comment), method: :post, remote: true, class: 'btn btn-xs btn-default' %>
<% end %>
// app/views/favorites/create.js.erb

$('#comment_<%= @favorite.comment.id %>').html("<%=j render 'favorites/favorite_button', comment: @favorite.comment , favorite: @favorite %>");
// app/views/favorites/destroy.js.erb

$('#comment_<%= @favorite.comment.id %>').html("<%=j render 'favorites/favorite_button', comment: @favorite.comment , favorite: @favorite %>");
# app/controllers/favorites_controller.rb

class FavoritesController < ApplicationController
  def create
    @favorite = Favorite.find_or_create_by(comment_id: params[:comment_id], user_id: current_user.id)
    render layout: nil
  end

  def destroy
    @favorite = Favorite.find_by(params[:id])
    @favorite.destroy
  end
end

確認

$ rails s


こんな感じでやった気がする。
もっとスマートなやり方が知りたいっす。