这是在Rails应用程序中更新属性的“正确”方法吗?

时间:2012-01-23 15:06:24

标签: ruby-on-rails ruby ruby-on-rails-3 activerecord

谢谢你的期待。我正在学习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方式是什么?

非常感谢!

4 个答案:

答案 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方式来做到这一点