【问题标题】:Rails: Allow users to upvote only once a pinRails:允许用户只对一个 pin 点赞一次
【发布时间】:2014-07-06 14:03:19
【问题描述】:

我的 rails 应用程序中有一个投票系统,允许用户为 Pin 图投票。 但我想限制一个 Pin 只点赞一次的能力。

app/controllers/pins_controller.rb

  def upvote
    @pin = Pin.find(params[:id])
    @pin.votes.create
    redirect_to(pins_path)
  end

app/models/pin.rb

class Pin < ActiveRecord::Base

    belongs_to :user

    has_many :votes, dependent: :destroy

    has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }
    has_attached_file :logo, :styles => { :medium => "300x300>", :thumb => "100x100>" }

    end

app/config/routes.rb

  resources :pins do
  member do
    post 'upvote'
  end
end

我不确定如何实现这一点,因为我试图实现一个只允许用户投票一次的系统,这不是我想要的,我希望他们能够只投票一次“PIN”。 我知道acts_as_votable gem 提供了这个功能,但由于我没有使用它,我想知道是否有办法在我自己的代码上实现它。

有什么想法吗?

更新:此方法仅允许每个引脚投一票。见@Ege解决方案

让它与这个一起工作:

def upvote
  @pin = Pin.find(params[:id])

  if @pin.votes.count == 0
     @pin.votes.create
     redirect_to(pins_path)
  else flash[:notice] =  "You have already upvote this!"
    redirect_to(pins_path)
end
end

【问题讨论】:

    标签: ruby-on-rails ruby vote pins


    【解决方案1】:

    您选择了 beautifulcoder 的答案作为正确答案,但您应该知道它可能不正确,如果您是 Rails 新手,这可能并不明显。

    您说 Pin 应该只有一票,但大概您的意思是每个用户应该有一个投票,例如,每个用户应该只能对 Pin 投票一次。这就是投票机制通常的工作方式。

    对于beautifulcoder 的回答,如果我给Pin 点赞,您将无法点赞,因为您的控制器会计算Pin 上的投票数,返回1(因为我点赞了它)并阻止您点赞。此外,它会闪烁一条消息,说你已经投票了,而你还没有!

    如何解决这个问题?幸运的是,Rails 让这一切变得超级简单。你的投票实际上是一个变相的加入模型。它在用户和 pin 之间建立关系(即关联)。用户可以对 pin 进行投票,并且 pin 可以由用户投票。换句话说,投票“连接”用户和引脚!您需要做的是通过利用ActiveRecord Associations 来定义这种关系。

    您的 Pin 模型将添加此关联:

    class Pin < ActiveRecord::Base
    
      has_many :votes, dependent: :destroy
      has_many :upvoted_users, through: :votes, source: :user
    
      ...
    
    end
    

    这使您可以执行@pin.upvoted_users 之类的操作,并获取对该 pin 投了赞成票的用户列表。如果您希望能够通知 pin 所有者,那就太好了!

    您还想为您的用户模型添加反向关联:

    class User < ActiveRecord::Base
    
      has_many :votes, dependent: :destroy
      has_many :upvoted_pins, through: :votes, source: :pin
    
      ...
    
    end
    

    然后像这样改变投票模型:

    class Vote < ActiveRecord::Base
    
      belongs_to :user
      belongs_to :pin
      validates_uniqueness_of :pin_id, scope: :user_id
    
    end
    

    最后在你的控制器中,你会这样做:

    def upvote
      @pin = Pin.find(params[:id])
    
      if @pin.votes.create(user_id: current_user.id)
        flash[:notice] =  "Thank you for upvoting!"
        redirect_to(pins_path)
      else 
        flash[:notice] =  "You have already upvoted this!"
        redirect_to(pins_path)
      end
    end
    

    瞧!您现在有了一个解决方案,用户可以对项目进行投票,但每个项目只能投票一次。

    【讨论】:

    • 你好@Ege 我真的很感谢你的回答,你真的很好。问题是,当我尝试对 pin 进行投票时,使用您的方法时遇到错误:未知属性:user_id
    • 如果您的投票模型没有 user_id 整数,您需要通过迁移添加它。如果您考虑一下,这是有道理的:投票属于用户,因此他们的模型应该有一个 user_id 外键。
    • 这是正确的答案。我会在 User 模型上创建一个投票方法并调用 current_user.vote(@pin) 以使其更易于理解。
    • @Ege 谢谢我在我的投票列中添加了一个 user_id 整数,现在它运行良好。唯一的问题是快闪消息——当我多次投票时,我只接受一次我想要的投票——但快闪消息保持不变,即使它没有因为用户已经投票而没有投票,他得到了闪信:“感谢投票”
    【解决方案2】:

    对控制器操作条件的小更新

    def upvote
      @pin = Pin.find(params[:id])
      @pin.votes.create(user_id: current_user.id)
    
      if @pin.save
        flash[:notice] =  "Thank you for upvoting!"
        redirect_to(pins_path)
      else 
        flash[:notice] =  "You have already upvoted this!"
        redirect_to(pins_path)
      end
    end
    

    【讨论】:

      猜你喜欢
      • 2017-02-26
      • 2014-02-11
      • 1970-01-01
      • 2019-11-19
      • 1970-01-01
      • 2015-03-12
      • 1970-01-01
      • 1970-01-01
      • 2013-05-18
      相关资源
      最近更新 更多