谢谢你的期待。我正在学习rails并正在构建一个Web应用程序。我试图成为“RESTful”并用这些术语思考。因此,我将我的数据视为资源。假设我有一个名为microposts的表和一个“投票”列,其中计算了有多少人投票或投票。我这样做了:
在视图中:
<td>
<%= form_for feed_item do |f| %>
<div><%= hidden_field_tag 'todo', 'upvote' %></div>
<div class="action"><%= f.submit "Up" %></div>
<% end %>
</td>
<td>
<%= form_for feed_item do |f| %>
<div><%= hidden_field_tag 'todo', 'downvote' %></div>
<div class="action"><%= f.submit "Down" %></div>
<% end %>
<td>
当用户点击该按钮时,它会调用控制器中的“更新”方法。然后,在控制器中,我有更新:
def update
@todo = params[:todo]
if @todo == "upvote"
Micropost.find(params[:id]).increment!(:votes)
flash[:success] = "Increase micropost vote"
redirect_to root_path
elsif @todo == "downvote"
Micropost.find(params[:id]).decrement!(:votes)
flash[:success] = "Decrease micropost vote"
redirect_to root_path
else
redirect_to root_path
end
end
我通过一个隐藏的字段来知道按下的按钮是“upvote”还是“downvote”。所以,如果我想改变任何其他微博属性,我需要有越来越多的if语句。我不认为我这样做是对的。更新数据库中的属性或记录的rails方式是什么?
非常感谢!
答案 0 :(得分:4)
我会创建其他操作upvote
/ downvote
(或仅vote
)并将其添加为member
资源。 REST并不仅限于CRUD,您可以随时添加其他操作。例如,在Rails 2中它将是:
map.resources :my_resource, :member => {:upvote => :put}
然后您可以使用upvote_my_resource_path
并向控制器添加upvote
操作,这样您就不会陷入update
。
答案 1 :(得分:3)
更RESTful的重做是将每个操作定义为单独的路由,如果必须,请进行GET,理想情况下,接收以下每种类型的调用:
before_filter :load_micropost
def load_micropost
@micropost = Micropost.find(params[:id])
end
def upvote
@micropost.increment!(:votes)
flash[:success] = "Increase micropost vote"
redirect_to root_path
end
def downvote
@micropost.decrement!(:votes)
flash[:success] = "Decrease micropost vote"
redirect_to root_path
end
不要忘记创建像load_micropost
这样的方法来处理模型的例行加载。对你的方法散布几个不同的调用是没有意义的,在未来的某个时候,可能需要调整。
你可以这样路由:
map.resources :microposts,
:member => {
:upvote => :post,
:downvote => :post
}
您可能需要考虑的另一件事是添加一个表格,记录谁投票的内容,以便您可以根据需要进行审核和调整。这样可以轻松解除任何欺诈活动,而无需重新批准选票。
如果您要求,也可以制作POST的简单链接:
<%= link_to('Upvote', upvote_micropost_path(feed_item), :method => :post) %>
这将负责渲染所需的任何表单元素。
答案 2 :(得分:1)
我会将投票保存在单独的模型Vote
(micropost_id, user_id, positive, created_at)
中,同时将字段添加到微博votes
或类似的内容,其中包含(count_up_votes - count_down_votes)
。
之后我将在微博下创建新资源votes
,因此您将拥有micropost_votes_path
之类的路线。
如果您选择该设计,您的用户将可以取消他们的投票,并且您将能够阻止每位用户多次投票。
答案 3 :(得分:0)
首先,为模型添加虚拟属性:
Class Micropost
def change_vote(value)
if value == 'upvote'
votes += 1
elseif value == 'downvote'
votes -= 1
end
end
end
然后在你的表单中,一定要使用表单助手:(假设feed_item是一个微博)
<%= form_for feed_item do |f| %>
<div><%= f.hidden_field 'change_vote', 'upvote' %></div>
<div class="action"><%= f.submit "Up" %></div>
<% end %>
这将以适当的形式为REST提供资源。所有控制器需要做的是:
def update
@mp = Micropost.find(params[:id])
@mp.update_attributes(params[:micropost])
if params[:micropost][:change_vote] == 'upvote'
flash[:success] = "Increase micropost vote"
else
flash[:success] = "Decrease micropost vote"
end
redirect_to root_url
end
当然,这并没有考虑到验证等等,但这是RESTful方式来做到这一点