Rails3.2で、スター機能(Likeやお気に入り)を実装しようとしたら、思いの外サンプルが見つからなかったので書いてみる。とりあえず動く。おk。
ルーティング
#config/routes 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 # starable_forでは下記をチェック # ・投稿者がユーザー自身の場合はお気に入りさせない # ・お気に入りを重複させない
#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
</pre> #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 <pre>
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側に書いてあります。うーん、良いのか悪いのか。
下記の本が大変参考になりました。これをベースに、Controller、URL一本化、Ajax化などの変更を行なっています。