【问题标题】:How would I go with refactoring my controller's custom methods?我将如何重构控制器的自定义方法?
【发布时间】:2014-07-15 19:31:06
【问题描述】:

我正在构建一个类似于 StackOverflow 的克隆用于学习目的。用户可以为某人的问题投票,从而提高或降低其分数。我的方法效果很好,但是重复和控制器逻辑的数量让我很困扰。

  • 用户 has_many 投票
  • 问题 has_many Votes
  • 投票属于问题/用户

路线:

concern :voteable do
  post 'votes/voteup',   to: 'votings#voteup',   as: :voteup
  post 'votes/votedown', to: 'votings#votedown', as: :votedown
end

resources :questions, concerns: [:commentable, :favoriteable, :voteable] do
  ...
end

投票控制器

class VotingsController < ApplicationController
  def voteup
    @question = Question.find(params[:question_id])

    unless @question.user == current_user # checks if the user is the author
      if current_user.voted?(@question.id) #checks if user already voted
        @vote = current_user.votes.find_by(question_id: @question)
        @vote.update_attributes(score: 1)
      else
        @vote = Vote.create(user: current_user, question: @question, score: 1)
      end
    end

    redirect_to :back
  end

  def votedown
    @question = Question.find(params[:question_id])

    unless @question.user == current_user
      if current_user.voted?(@question.id) 
        @vote = current_user.votes.find_by(question_id: @question)
        @vote.update_attributes(score: -1)
      else
        @vote = Vote.create(user: current_user, question: @question, score: -1)
      end
    end

    redirect_to :back
  end
end

voted?是我提取到我的用户模型的方法

  def voted?(question)
    true if self.votes.where(question_id: question) 
  end

我想摆脱这两种方法中的重复,但是如何呢? 我是否应该创建一种像 VOTE 这样的方法和一条使用指定参数(上/下)通向它的路线,然后根据 if/else 分配分数?对我来说听起来很脏,但这是我唯一想到的。我确信必须有一个漂亮的 Rails 方式来解决这个问题。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4


    【解决方案1】:

    User 类可以包含一个名为 vote_for(question, score) 的方法,并定义如下:

    # class User
    def vote_for(question, score)
      vote = self.votes.where(question_id: question.id).first || Vote.new(user: self, question: question)
      vote.score = score
      vote.save
    end
    
    
    class VotingsController < ApplicationController
      before_filter :set_question, only: %w(voteup votedown)
    
      def voteup
        current_user.vote_for(@question, 1)
      end
    
      def votedown
        current_user.vote_for(@question, -1)
      end
    
      protected
      def set_question
        @question = Question.find(params[:id])
      end
    

    一个小提示:您应该将 User 类的 .voted? 方法重构为:

    def voted?(question)
      self.votes.exists?(question_id: question)
    end
    

    这将返回 TRUE 或 FALSE,而不是从 DB 中检索然后转换为 Ruby 对象的完整对象。

    【讨论】:

    • 谢谢。我按照你的方式进行了一些重构,我的代码现在看起来好多了
    猜你喜欢
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-02
    • 1970-01-01
    相关资源
    最近更新 更多