用于与link_to一起使用的单击事件的控制器逻辑

时间:2013-01-25 03:30:00

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

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

目前,我的模型Questionhas_many answers。此外,我制作了Selection模型,用于表示答案选择,其中每个Question只能has_one选择答案。

我在问题的show动作中回答每个问题的答案和问题。在我的_answer部分中,我想提出以下逻辑:“如果提出问题的用户已登录,他可以看到链接'取消选择'答案如果相关selection已经存储了answer_id的答案(换句话说,标记此答案之前已被选中),否则他可以“选择”将答案存储在{answer_id中的答案selection 1}}。(我应该提一下,我在Rails tutorial处修改了下面的大部分代码,其中我(遗憾的是)我不太清楚如何使用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 %>

我的包版广告位于控制器中,如果用户通过“{{1}”方法将the create变量分配给新的@selection,我将无法通过“选择”链接。任何帮助,或任何关于如何写点击事件的指南将非常感激。谢谢!

1 个答案:

答案 0 :(得分:1)

有很多不同的方法可以做到这一点,但我倾向于认为你有设计问题,所以这就是我将如何做到这一点。

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

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

此直观表示清楚地显示了问题:您的Selection模型是多余的,因为它代表了问题belongs_toUser(我们已经知道)的事实;如果每对Question / User可以有多个选择,那就不会多余,但实际上我们希望这对于每对夫妇来说都是唯一的......

belongs_toQuestion之间的Answer关系可以实现与Selection模型相同的功能,事实上它可以做得更好因为您不需要所有逻辑来找到正确的选择,并确保它是唯一的/用户是问题的正确拥有者等。

所以这就是我要做的事情:

  • 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 %>