Rails:允许用户仅对引脚进行一次upvote

zac*_*chj 2 ruby ruby-on-rails vote pins

我的rails应用程序中有一个upvote系统,允许用户提升Pin.但是我想限制只有一次Pin的upvote的能力.

应用程序/控制器/ pins_controller.rb

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

应用程序/模型/ 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
Run Code Online (Sandbox Code Playgroud)

应用程序/配置/ routes.rb中

  resources :pins do
  member do
    post 'upvote'
  end
end
Run Code Online (Sandbox Code Playgroud)

我不确定如何实现这一点,因为我试图实现一个允许用户只投票一次的系统,这不是我想要的,我希望他们能够只投票一次"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
Run Code Online (Sandbox Code Playgroud)

Ege*_*soz 12

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

你说一个引脚只拥有一票,但想必你的意思是,它应该有一票表决权每个用户,如,每个用户应该能够给予好评销钉只有一次.这就是投票机制通常如何运作.

有了beautifulcoder的答案,如果我upvote一个Pin,你将无法进行投票,因为你的控制器将计算Pin上的投票数,返回1(因为我赞成它)并阻止你进行投票.此外,它会闪烁一条消息,说你已经赞成它,而你却没有!

如何解决这个问题呢?幸运的是,Rails让这非常容易.您的投票实际上是伪装的加入模型.它建立了用户和引脚之间的关系(即关联).用户可以对引脚进行upvote,并且可以由用户对引脚进行upvoted.换句话说,投票"连接"用户和引脚!您需要做的是通过利用ActiveRecord关联来定义此关系.

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

class Pin < ActiveRecord::Base

  has_many :votes, dependent: :destroy
  has_many :upvoted_users, through: :votes, source: :user

  ...

end
Run Code Online (Sandbox Code Playgroud)

这允许你做类似的事情,@pin.upvoted_users并得到一个赞成该引脚的用户列表.非常好,如果你想通知别人的主人!

您还希望向User模型添加反向关联:

class User < ActiveRecord::Base

  has_many :votes, dependent: :destroy
  has_many :upvoted_pins, through: :votes, source: :pin

  ...

end
Run Code Online (Sandbox Code Playgroud)

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

class Vote < ActiveRecord::Base

  belongs_to :user
  belongs_to :pin
  validates_uniqueness_of :pin_id, scope: :user_id

end
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

瞧!您现在有一个解决方案,用户可以在其中投票,但每个项目只能投票一次.

  • 这是正确的答案.我会在User模型上创建一个投票方法,并调用current_user.vote(@pin)以使其更容易理解. (2认同)