over 1 year ago

实现思路:参考Rails101教程

如果认真练习过Rails101 5次以上的话,应该可以很快联想起来商品收藏功能的做法,非常相似于”用户“与“群组”的关系。

对比如下:
- 有许多不同的User,也有许多不同的Group
- User可以选择加入任一个或者几个Group
- Group也可以包含不同的User
VS
- 有许多不同的User,也有许多不同的Product
- User可以选择收藏任一个或者几个Product
- Product也可以被不同的User收藏

所以,我们完全可以参考 Rails101 教程7.1~7.5 来实现收藏商品的后台功能,再加上 “按钮的美化” 和“收藏icon” ,就是一个完整的收藏功能了。
另外,参考 Rails101 教程8 来查看我收藏过的商品


收藏功能具体实做步骤

Step 1: 建立 ProductRelationship

新建一个model,记录哪个User收藏了哪个Product。
rails g model favorite group_id:integer user_id:integer
执行 rake db:migrate

Step 2: 建立 Product与User之间的收藏关系
app/models/user.rb
.. 略
+    has_many :favorites
+    has_many :favorited_products, :through => :favorites, :source => :product
.. 略

然后修改 app/models/favorite.rb,加入这两行

app/models/favorite.rb
class Favorite < ApplicationRecord
+  belongs_to :user
+  belongs_to :product
end

这样当捞 user.favorited_products 时,就会捞出“收藏的商品”。

修改 app/models/product.rb,加入这两行

.. 略
+  has_many :favorites
+  has_many :favorited_users, :through => :favorites, :source => :user
.. 略
Step 3: 在 user model 内实作判断式“是否收藏”
app/models/user.rb
.. 略
+  def is_like?(product)
+    favorited_products.include?(product)
+  end
.. 略
Step 4: 在 products/show.html.erb 内加入”是否收藏“状态
app/views/products/show.html.erb
<span>
  <% if current_user && current_user.is_like?(@product) %>
    <label class="label label-success"> 收藏商品 </label>
  <% else %>
    <label class="label label-success"> 未收藏商品 </label>
  <% end %>
</span>

Step 5: 在 user model 内实作”收藏商品“及“取消收藏商品”
app/models/user.rb
.. 略
  def like!(product)
    favorited_products << product
  end

  def unlike!(product)
    favorited_products.delete(product)
  end
.. 略
Step 6: 实际操作”收藏商品“及“取消收藏商品”
app/controllers/products_controller.rb
.. 略
 def like
   @product = Product.find(params[:id])
   if !current_user.is_like?(@product)
       current_user.like!(@product)
       flash[:notice] = "收藏商品成功!"
    else
       flash[:warning] = "你已经收藏过本商品了!"
    end
     redirect_to product_path(@product)
 end

 def unlike
   @product = Product.find(params[:id])
   if current_user.is_like?(@product)
       current_user.unlike!(@product)
       flash[:notice] = "取消收藏商品!"
    else
       flash[:warning] = "你没有收藏过商品,如何取消 XD!"
    end
     redirect_to product_path(@product)
 end
.. 略

”收藏商品“及“取消收藏商品”必须要是登入状态下才行。加入下面一行

app/controllers/products_controller.rb
  before_action :authenticate_user! , only: [:like, :unlike]

.. 略
Step 7: 修改routes
config/routes.rb
.. 略
  resources :products do
  
    member do
      post :add_to_cart
+     post :like
+     post :unlike
    end
    
    resources :posts
  end
.. 略
Step 8: 修改”收藏商品“及“取消收藏商品”按钮
app/views/products/show.html.erb
<span>
  <% if current_user && current_user.is_like?(@product) %>
-   <label class="label label-success"> 收藏商品 </label>
+   <%= link_to("取消收藏 ☆ ", unlike_product_path(@product), method: :post, class: "btn btn-default" ) %>
  <% else %>
-   <label class="label label-success"> 未收藏商品 </label>
+   <%= link_to("收藏商品 ❤ ", like_product_path(@product), method: :post, class: "btn btn-default" ) %>
  <% end %>
</span>


下拉菜单,看到我收藏过的商品

Step 1: 产生 account 的 namespace 下的 favorites_controller

执行
rails g controller account/favorites

Step 2. 修改 routing

修改 config/routes.rb 加入:

config/routes.rb
.. 略
  namespace :account do
    resources :orders
+   resources :favorites
  end
.. 略
Step 3. 修改下拉菜单,增加选项

修改 app/views/common/_navbar.html.erb 加入:

app/views/common/_navbar.html.erb
.. 略
   <ul class="dropdown-menu">
     <li> <%= link_to("My orders", account_orders_path ) %></li>
+    <li> <%= link_to("我的收藏", account_favorites_path) %></li>
.. 略
   </ul>
.. 略

为了美化效果,加入收藏icon,可以将上述代码修改为

app/views/common/_navbar.html.erb
<li> 
-  <%= link_to("我的收藏", account_favorites_path) %>
+  <%= link_to account_favorites_path do %> 我的收藏 <i class= "fa fa-heart fa-md"></i>
+  <% end %>
</li>
Step 4.建立 account/favorites_controller.rb 下的 index action
app/controllers/account/favorites_controller.rb
class Account::FavoritesController < ApplicationController
  before_action :authenticate_user!

  def index
    @products = current_user.favorited_products
  end
end

Step 5. 新增 “收藏商品一览页面”

touch app/views/account/favorites/index.html.erb

可以直接使用app/views/products/index.html.erb页面

app/views/account/favorites/index.html.erb
<div class="row">
  <% @products.each do |product| %>
    <div class="col-xs-6 col-md-3">
      <%= link_to product_path(product) do %>
        <% if product.image.present? %>
          <%= image_tag(product.image.thumb.url, class: "thumbnail") %>
        <% else %>
          <%= image_tag("http://placehold.it/200x200&text=No Pic", class: "thumbnail") %>
        <% end %>
      <% end %>
      <%= product.title %> ¥ <%= product.price %>
    </div>
  <% end %>
</div>

也可以使用app/views/admin/products/index.html.erb页面

app/views/account/favorites/index.html.erb
<div class="row">
    <div class="col-md-10">
        <h2>我收藏的商品</h2>
        <table class="table table-bordered">
            <thead>
                <tr>
                    <th>#</th>
                    <th width="220">Product Pic</th>
                    <th>Name</th>
                    <th>Price</th>
                </tr>
            </thead>
            <tbody>
              <% @products.each do |product| %>
                <tr>
                  <td> <%= product.id %> </td>
                  <td> <%= link_to product_path(product) do %>
                       <% if product.image.present? %>
                         <%= image_tag(product.image.thumb.url, class: "thumbnail") %>
                       <% else %>
                         <%= image_tag("http://placehold.it/200x200&text=No Pic", class: "thumbnail") %>
                        <% end %>
                       <% end %>
                   </td>
                   <td> <%= product.title %> </td>
                   <td> <%= product.price %> </td>
                 </tr>
                <% end %>
            </tbody>
        </table>
    </div>
</div>





至此,收藏功能已经完成。
文末,分享一点小技巧。
在实做收藏功能时,首先,我确认参考Rails01的思路是对的,但是在具体实做过程中,要按照教程进行实际操作,同时需要考虑到model、method名称的改变,一不小心,很容易出错。如何解决呢? 我用纸笔直接画出来。

1.按原教程在纸上用蓝色笔写出 User 、Group 、及相关的method。
2.每实做一步,在蓝色字体旁边,标注实做的 medle及method名称。
3.这样,就很容易按步骤进行,而不会遗漏或者弄错名称。

当然,如果你对教程中的内容和前后步骤已经相当熟悉了,自然不需要这种土办法了。



你好,如果觉得这篇文章对你有帮助,我最近在参加一个编程比赛,JD-Store 魔改大赛,喜欢的话还麻烦你投下宝贵的一票,谢谢。

← JDStore魔改-product搜索功能汇总-20170603 【魔改复盘】一个留级生的自我救赎 →
 
comments powered by Disqus