1

我有兴趣制作一个类似于 SO 的功能,其中提出问题的用户可以从响应列表中选择一个答案,但被困在如何从控制器的角度处理点击事件。

目前,我有模型Question,其中has_many answers. 另外,我做了一个Selection模型,用来象征答案的选择,每个Question人只能has_one选择答案。

我将每个问题的答案与问题show操作中的问题一起呈现。在我的_answer部分中,我想放置以下逻辑:“如果提出问题的用户已登录,如果相关selection人员answer_id已经存储了该答案,他可以看到“取消选择”答案的链接(换句话说,标记这个答案是以前选择的),否则他可以“选择”将答案存储在 中的答案answer_idselection(我应该提到我从Rails 教程这里改编了下面的大部分代码,我(不幸的是)没有扎实的理解如何使用POST匹配或分配属性给实例变量)

  <% if current_user?(answer.question.user) %>
    <% if current_user.selections.where(:answer_id => answer.id) == answer.id %>
      <%= link_to "unselect", selections_path(:selection => {:answer_id => nil}), :method => :post %>
    <% else %>
      <%= link_to "select", selections_path(:selection => {:answer_id => answer.id}), :method => :post %>
    <% end %>
  <% end %>

我的路障在控制器中,如果用户通过“选择”链接选择新答案,我会被困在如何使用the create方法将@selection变量分配给新的变量。answer_id任何帮助或任何关于如何编写点击事件的指南将不胜感激。谢谢!

4

1 回答 1

1

有很多不同的方法可以做到这一点,但我倾向于认为你在这里有一个设计问题,所以我会这样做。

我从你所说的假设你的关联看起来像这样:

 __________                                  ________
| Question |1                              *| Answer |
|          |<-------------------------------|        |
|          |1     * ___________ *          1|        |
|          |<------| Selection |----------->|________|
|          |       |           |            
|          |       |           |*          1 ________
|          |       |___________|----------->| User   |
|          |*                              1|        |
|__________|------------------------------->|________|

这种视觉表示清楚地表明了问题:您的Selection模型是多余的,因为它代表了一个问题belongs_toa User(我们已经知道)的事实;如果每对可以有多个选择,那将不会是多余的Question / User,但实际上我们希望该选择对于每对都是唯一的......

和之间的belongs_to关系将实现与您的模型相同的事情,实际上它会做得更好,因为您不需要所有逻辑来找到正确的选择,并确保它是唯一的/用户是正确的问题的所有者等QuestionAnswerSelection

所以这就是我要做的:

  • Question模型中

    has_many   :answers,         inverse_of: :question
    belongs_to :accepted_answer, class_name: :answer, foreign_key: :accepted_answer_id
    
  • Answer模型中

    belongs_to :question, inverse_of: :answers
    
    def accepted?
      return false if new_record? 
      question.try( :accepted_answer_id ) == id
      # an alternative is to use question.try( :accepted_answer ) == self
    end
    
  • 在您的路线中

    resources :questions do
      member do 
        # we use put because these are update actions
        put :accept_answer
        put :clear_accepted_answer
      end
    end
    
  • 在你的QuestionsController

    respond_to :js, only: [:accept_answer, :clear_accepted_answer]
    
    def accept_answer
      @question = Question.find( params[:id] )
    
      # ...cue some logic to ensure current_user 
      # has required rights to update the question
    
      if @question.update_attributes( accepted_answer_id: params[:answer_id] )
        # ...render the js that updates your view (for example, 
        # find and replace calling link with an "unselect" one )
      else
        # .. an error has occurred, render an "unprocessable entity" status
      end
    end
    
    
    def clear_accepted_answer
      @question = Question.find( params[:id] )
    
      # ...cue some logic to ensure current_user 
      # has required rights to update the question
    
      if @question.update_attributes( accepted_answer_id: nil )
        # ...render the js that updates your view (for example, 
        # find and replace calling link with a "select" one )
      else
        # .. an error has occurred, render an "unprocessable entity" status
      end
    end    
    
  • 在你看来

      <% if current_user?(answer.question.user) %>
        <% if answer.accepted?  %>
          <%= link_to "unselect", 
                      clear_accepted_answer_question_path( answer.question ),
                      method: :put,
                      remote: true %>
        <% else %>
          <%= link_to "select", 
                      accept_answer_question_path( 
                        answer.question, 
                        answer_id: answer.id 
                      ), 
                      method: :put,
                      remote: true %>
        <% end %>
      <% end %>
    
于 2013-01-26T18:19:06.463 回答