【问题标题】:How do I limit users to "liking" a post only once in ruby on rails?如何限制用户在 ruby​​ on rails 中只“喜欢”一次帖子?
【发布时间】:2012-06-09 12:26:17
【问题描述】:

基本上,我有一个列出 10 条最新微博的页面。每个帖子都有一个赞按钮。单击此赞按钮时,我的数据库中的赞表将更新。

赞表:

+----+------------+--------------+-------------------------+-------------------------+---------+
| id | likable_id | likable_type | created_at              | updated_at              | user_id |
+----+------------+--------------+-------------------------+-------------------------+---------+
| 2  | 5770       | Micropost    | 2012-06-09 11:30:55 UTC | 2012-06-09 11:30:55 UTC | 2       |
| 3  | 5770       | Micropost    | 2012-06-09 11:42:45 UTC | 2012-06-09 11:42:45 UTC | 2       |
+----+------------+--------------+-------------------------+-------------------------+---------+

用户只能为微博点赞一次。我可以使用一些 jquery/js 来实现这一点,方法是在喜欢微博时显示一个指向销毁路径的不同按钮。

但是有没有办法在服务器端也做这个?就像不允许以任何必要的方式多次喜欢微博一样?因此,如果我要进入 Rails 控制台并尝试手动点赞我已经喜欢的微博,它不会起作用,因为它会看到我已经喜欢微博?

喜欢的模特:

class Like < ActiveRecord::Base
  belongs_to :likable, :polymorphic => true
  attr_accessible :likable_id, :likable_type, :user_id
end

微博模型:

class Micropost < ActiveRecord::Base
    belongs_to :user
    has_many :likes, :as => :likable
end

喜欢控制器:

class LikesController < ApplicationController
  def create
    micropost = Micropost.find(params[:micropost])
     like = micropost.likes.build(:user_id => current_user.id)
     like.save
  end
end

点赞形式:

<%= form_tag likes_path, :remote => true, :class => "like_micropost" do %>  
   <%= hidden_field_tag :micropost, micropost.id %>
       <%= submit_tag '', :class => "likeMicropostSubmit"  %> 
<% end %>

我之前尝试过,但没有成功:

class LikesController < ApplicationController
  def create
    micropost = Micropost.find(params[:micropost])
    if micropost.likes.where(:user_id => current_user.id).nil?
     like = micropost.likes.build(:user_id => current_user.id)
     like.save
    end
  end
end

亲切的问候

【问题讨论】:

  • 那么,问题是什么?在LikesController#create 中搜索来自该用户的现有赞并采取相应行动。

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


【解决方案1】:
# in Like class
validates_uniqueness_of :user_id, :scope => [:likable_id, :likable_type]

这样你会在尝试多次喜欢某样东西时收到验证错误。

See docs for it.

【讨论】:

  • 不敢相信我忘记了那个验证规则。在 CSS/Jquery 上花费了太多时间。不错的简单解决方案。谢谢
  • 这在技术上仍然有效,但在 Rails 3+ 应用程序中通常首选新的验证语法:validates :uniqueness =&gt; true, :user_id, :scope =&gt; [:likable_id, :likable_type]
【解决方案2】:

我会做两件事:

  1. 将创建逻辑移至模型(胖模型、瘦控制器)
  2. 在类似创建时添加验证(正如 jdoe 已经说过的)

所以:

class LikesController < ApplicationController
  def create
    micropost = Micropost.find(params[:micropost])
    current_user.likes! micropost
  end
end

class Like < ActiveRecord::Base
  validates_uniqueness_of :user_id, :scope => [:likable_id, :likable_type]
end

class User < ActiveRecord::Base
  # exclamation mark to avoid confusion between things that are liked by the user
  def likes!(likable_object)
    unless likable_object.likes.where(:user_id => self.id).exists?
      like = likable_object.likes.build(:user_id => self.id)
      like.save
    end
  end
end

编辑:解释:

1) 管理 Like 创建阶段是模型的职责 -> 将管理创建的代码移至模型

2) 为描述动作找到一个好的方法名称 -> User.likes! something 听起来不错

3) 实现创建方法->

def likes!(likable_object)
  like = likable_object.likes.build(:user_id => self.id)
  like.save
end

4) 添加验证以管理模型有效/模型无效逻辑 -> class Like; validates_uniqueness_of ...

5) 让likes! 方法意识到有效/无效逻辑 ->

def likes!(likable_object)
  unless likable_object.likes.where(:user_id => self.id).exists?
    like = likable_object.likes.build(:user_id => self.id)
    like.save
  end
end

【讨论】:

  • 如果您仍然手动检查“喜欢”,validates_uniqueness_of 有什么好处?奇怪的决定...
  • 好处是,如果您在某处有错误导致应用程序创建重复,验证失败并且您的数据库保持一致,即:“重复记录有效吗?” "否" "添加使其无效的验证"
  • 有了这种怀疑,您将永远不会对任何验证感到满意,不是吗? :)
  • 不,您对添加所需的验证感到满意 :) 验证的目的是使模型实例有效或无效,因此使用它们来获得该结果是正确的(恕我直言:- ) )
【解决方案3】:

好的,这对我有用:

class LikesController < ApplicationController
  def create
    micropost = Micropost.find(params[:micropost])
    unless micropost.likes.where(:user_id => current_user.id).exists?
     like = micropost.likes.build(:user_id => current_user.id)
     like.save
    end
  end
end

没有创建模板是它无法正常工作的原因,但模板是空的且未使用,所以想知道为什么它是强制性的。

【讨论】:

  • 数据一致性不是控制器的任务!
猜你喜欢
  • 2019-08-13
  • 2019-10-06
  • 1970-01-01
  • 1970-01-01
  • 2012-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多