赵龙 全栈之路

加分题 第二课. 3-13 加一个“扣分”按钮

| Comments

3-13 加分题 & 下一步

解题思路

回顾之前的教材步骤,投票功能的实现——upvote(即加分),是在“3-9 让大家可以投票”这一节里实现的。仿效这一节,可以实现“扣分”功能。

实作

步骤1:加一个新的 controller action 来投票减分

app/controllers/topics_controller.rbprivate上方增加reduce的 method

app/controllers/topics_controller.rb
def reduce
  @topic = Topic.find(params[:id])
  @topic.votes.first.destroy
  redirect_to(topics_path)
end

注意:upvote的 method 是topic.votes.create,而reduce的 method 不是topic.votes.destroy,而是topic.votes.first.destroy。这个讯息是从3-8 把投票记录和 Topics 接起来中找到的。
实践证明topic.votes.destroy无法实现删除投票。

步骤2:给投票减分操作加一个 route

config/routes.rb 中增加一个 reduce 的 route:

config/routes.rb
member do
  post 'reduce'
end

代码最后看起来变成这样:

config/routes.rb
Rails.application.routes.draw do
  root 'topics#index'
  resources :topics do
    member do
      post 'upvote'
    end
    member do
      post 'reduce'
    end
  end
end

一个小发现:

config/routes.rbpost 'upvote'下面增加一行post 'downvote',效果与上面的代码一样。代码最后看起来变成这样:

config/routes.rb
Rails.application.routes.draw do
  root 'topics#index'
  resources :topics do
    member do
      post 'upvote'
      post 'reduce'
    end
  end
end

检查 route 有没有成功加入,在 terminal 里输入rake routes,输入结果里应该多downvote_topic这一行,整个输出结果像这样

Prefix Verb   URI Pattern                    Controller#Action
  root GET    /                              topics#index
upvote_topic POST   /topics/:id/upvote(.:format)   topics#upvote
downvote_topic POST   /topics/:id/downvote(.:format) topics#reduce
topics GET    /topics(.:format)              topics#index
       POST   /topics(.:format)              topics#create
new_topic GET    /topics/new(.:format)          topics#new
edit_topic GET    /topics/:id/edit(.:format)     topics#edit
 topic GET    /topics/:id(.:format)          topics#show
       PATCH  /topics/:id(.:format)          topics#update
       PUT    /topics/:id(.:format)          topics#update
       DELETE /topics/:id(.:format)          topics#destroy

步骤3:在 view 里面加一个按钮

页面中要有扣分的按钮,这个一般在 views 文件夹下相应的 html 中实现。在 app/views/index.html.erbbutton_to '+1' 下面增加一行代码:

app/views/topics/index.html.erb
<td><%= button_to '-1', reduce_topic_path(topic), method: :post %></td>

步骤4:在浏览器里面检查修改成功

在终端执行rails server的情况下,打开 http://localhost:3000/topics ,在+1按钮后面多了一个-1

一点说明

这道题是自己解决的,写完之后发现实在是太简陋了,只是模仿教材的加分按钮实现目标,没有清晰的思路,也没有检验步骤,页面排版也很惨不忍睹。无意间google发现几位前辈的思路比我清晰多了,借鉴了。同时,我也有一个小发现。
参考思路1


google到学长的额外小发现,发现非常不错,借鉴下(参考思路2)。

发现一个问题,就是如果投票数是0的时候,会报错。


考虑到应该投票数为0的时候,就没法 destory 最后一个投票了,于是考虑应该增加一个判断,来限制如果投票数为0的时候,不应该再减少了,同时给个提示类似:“You cannot devote anymore!”最终修改代码如下,增加了投票数>0的时候才减少票数,其他情况下,都给出一个提示并返回 topics 列表。else 下面的代码格式也是参考之前 controller 里面其他代码的格式画瓢得来。

app/controllers/topics_controller.rb
  def reduce
    @topic = Topic.find(params[:id])
      if @topic.votes.count > 0
        @topic.votes.first.destroy
        redirect_to(topics_path)
      else
        respond_to do |format|
        format.html { redirect_to topics_url, notice: 'You can not devote anymore!' }
        format.json { head :no_content }
      end
    end
  end

最终得票数为0的时候,再点击‘-1’按钮的结果就会如下图:


然后又发现一个问题,就是减到0票的时候,后面的 votes 是复数,不知是何原因。于是又在 index.html.erb 文件中增加了一个 if 函数来判断。

app/views/index.html.erb
  <tbody>
    <% @topics.each do |topic| %>
      <tr>
        <td><%= link_to topic.title, topic %></td>
        <td>
          <% if topic.votes.count == 0 %>
           <%= "0 vote" %>
          <% else %>
           <%= pluralize(topic.votes.count, "vote") %>
          <% end %>
        </td>
        <td><%= button_to '+1', upvote_topic_path(topic), method: :post %></td>
        <td><%= button_to '-1', reduce_topic_path(topic), method: :post %></td>
        <td><%= link_to 'Delete', topic, method: :delete, data: { confirm: 'Are you sure?' } %>        </td>
      </tr>
    <% end %>
  </tbody>

最终得到的结果:

Comments

comments powered by Disqus