LoginSignup
25
24

More than 5 years have passed since last update.

Rails3.2でスター機能実装

Last updated at Posted at 2013-07-12

モデルは post、user、star 。20130706021155.jpg

ルーティング

# toggle_star
match 'toggle_star', :to => 'toggle_star#toggle_star', :via => [:get, :post]

View

app/view/posts/show.html.erb
<%=  form_tag({:controller => 'star', :action => 'toggle_star'}, {:name => 'toggle_star', :remote => true}) do %>
    <input type="hidden" value="<%= @post.id %>" name="post_toggle_star">
    <span class="js-toggle_star" data-num="<%= @post.id %>">スターボタン</span>
<% end %>

Model

app/models/post.rb
belongs_to :user
has_many :stars, :dependent => :destroy
has_many :stared_users, :through => :stars, :source => :user

# user -> post の関係を複数作る場合、別の名前(:stared_users)を付け、sourceオプションで本当の名前を指定するらしい。
app/models/user.rb
has_many :posts, :dependent => :destroy
has_many :stars, :dependent => :destroy
has_many :stared_posts, :through => :stars, :source => :post

def starable_for?(post)
  post && post.user != self && !stars.exists?(:post_id => post.id)
end

# postの有無
# 投稿者がユーザー自身の場合はお気に入りさせない
# 重複させない
app/models/star.rb
belongs_to :user
belongs_to :post
attr_accessible :user_id, :post_id

validate do
  unless user && user.starable_for?(post)
    return errors.add(:post_id)
  end
end

Controller

app/controllers/star_controller.rb
def toggle_star
  # ログインチェック
  raise unless login_user

  # 既にお気に入りしているかどうかチェック
  @post = Post.find(params[:post_toggle_star])
  if current_user.stared_posts.exists?(@post)
    render remove_star(@post)
  else
    render add_star(@post)
  end

  rescue
  render :json => {:result => "error" }, :status => 400 
end

# スターを追加
def add_star(postobj)
  current_user.stared_posts << postobj
  return  { :json => { :type => "add", :result => "success" } }
end

#スターを削除
def remove_star(postobj)
  current_user.stared_posts.delete(postobj)
  return  { :json => { :type => "remove", :result => "success" } }
end

JavaScript

// コールバックなどを設定。それぞれの処理に合わせたメソッドを作っていく
jQuery(formObj)
    .bind("ajax:loading", function(xhr){})
    .bind("ajax:success", function(data, status, xhr){})
    .bind("ajax:complete", function(xhr){})
    .bind("ajax:failure", function(xhr){});

スター/スター解除 でURLを共通にしたかったので、振り分ける分岐をController側に書いてあります。
URLを分けると、DBへのアクセスがもっと減るのかも。
↓ブログに書いたものの転載です。
http://www.rokurofire.info/2013/07/08/rails_star/

25
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
24