能够只喜欢这个帖子一次

时间:2015-12-23 14:36:02

标签: ruby-on-rails

我正在研究我的RoR应用程序的新功能。我已经实现了喜欢/不喜欢的系统,现在我想添加一次只喜欢帖子的能力(用户1可以喜欢或不喜欢Post 2一次)。我怎么能做到这一点。我想,我可以像这样做

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
 # validates :avatar, attachment_presence: true
  has_attached_file :avatar, styles: { medium: "300x300>", thumb: "100x100>" }
  validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\Z/

  has_and_belongs_to_many :posts

  def admin?
    admin
  end

end

 class Post < ActiveRecord::Base
  has_and_belongs_to_many :users
end

但除此之外,我还需要一个字段,这个has_and_belongs_to_many模型,它将是布尔字段,它告诉我是否为真 - 它是喜欢的,假的 - 它是不喜欢的。如何在此模型中访问此字段。我一点主意都没有 ?你能帮帮我吗?

我的schema.rb

ActiveRecord::Schema.define(version: 20151223102401) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "posts", force: :cascade do |t|
    t.integer "user_id"
    t.text    "text"
    t.integer "like",    default: 0
    t.integer "dislike", default: 0
  end

  create_table "posts_users", id: false, force: :cascade do |t|
    t.integer "post_id"
    t.integer "user_id"
    t.boolean "like"
  end

  create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "",    null: false
    t.string   "encrypted_password",     default: "",    null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,     null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.inet     "current_sign_in_ip"
    t.inet     "last_sign_in_ip"
    t.datetime "created_at",                             null: false
    t.datetime "updated_at",                             null: false
    t.string   "username"
    t.boolean  "admin",                  default: false
    t.string   "avatar_file_name"
    t.string   "avatar_content_type"
    t.integer  "avatar_file_size"
    t.datetime "avatar_updated_at"
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree

end

2 个答案:

答案 0 :(得分:1)

您考虑使用某些库吗?有一个宝石'act_as_votable',它完全符合您的要求。而且记录非常好。以下是github上的repo链接以及有关已注册投票的文档https://github.com/ryanto/acts_as_votable#registered-votes

答案 1 :(得分:1)

如果我理解你的问题,你有3个模特;用户,邮政和邮政用户。

并且,你想:

  1. 允许用户创建帖子
  2. 允许用户只喜欢或不喜欢该帖子一次
  3. 如果用户已经喜欢或不喜欢该帖子,请隐藏喜欢或不喜欢的按钮
  4. 根据喜欢或不喜欢的帖子,在like表格中为该帖子添加dislikeposts
  5. 好的,这是解决这种情况的解决方案。

    <强> schema.rb

    ActiveRecord::Schema.define(version: 20151226094953) do
    
      create_table "post_users", force: :cascade do |t|
        t.integer  "post_id"
        t.integer  "user_id"
        t.boolean  "already_like_or_dislike", default: false
        t.datetime "created_at",                              null: false
        t.datetime "updated_at",                              null: false
      end
    
      create_table "posts", force: :cascade do |t|
        t.string   "text"
        t.integer  "user_id"
        t.integer  "like",       default: 0
        t.integer  "dislike",    default: 0
        t.datetime "created_at",             null: false
        t.datetime "updated_at",             null: false
      end
    
      create_table "users", force: :cascade do |t|
        t.string   "email",                  default: "", null: false
        t.string   "encrypted_password",     default: "", null: false
        t.string   "reset_password_token"
        t.datetime "reset_password_sent_at"
        t.datetime "remember_created_at"
        t.integer  "sign_in_count",          default: 0,  null: false
        t.datetime "current_sign_in_at"
        t.datetime "last_sign_in_at"
        t.string   "current_sign_in_ip"
        t.string   "last_sign_in_ip"
        t.datetime "created_at",                          null: false
        t.datetime "updated_at",                          null: false
      end
    
      add_index "users", ["email"], name: "index_users_on_email", unique: true
      add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
    
    end
    

    发布模型

    class Post < ActiveRecord::Base
        belongs_to :user
        has_many :post_users
    end
    

    PostUser模型

    class PostUser < ActiveRecord::Base
        belongs_to :post
        belongs_to :user
    end
    

    用户模型(由Devise gem生成)

    class User < ActiveRecord::Base
      devise :database_authenticatable, :registerable,
             :recoverable, :rememberable, :trackable, :validatable
      has_many :posts
      has_many :post_users
    end
    

    好的,现在让我们来看看控制器的动作。

    首先,我向set_post行动添加了2个新动作:likedislike

    before_action :set_post, only: [:show, :edit, :update, :destroy, :like, :dislike]
    
    private
        def set_post
          @post = Post.find(params[:id])
        end
    

    显示操作

    def show
        if user_signed_in?
          if @post.post_users.find_by(user_id: current_user.id)
            @can_like_or_dislike = false
          else
            @can_like_or_dislike = true
          end
        end
      end
    

    首先,我们检查用户是否已登录。如果用户已登录,我们会尝试在post_users表格中找到post_id: @post.iduser_id: current_user.id的记录。

    如果我们找到了记录,这意味着,已登录的用户已经喜欢或不喜欢该帖子。因此,我们将false传递给@can_like_or_dislike变量。

    这就是我们的show模板的样子:

    <% if user_signed_in? %>
        <% if @can_like_or_dislike %>
            <%= link_to "Like", like_post_path, method: :post %>
            <%= link_to "Dislike", dislike_post_path, method: :post %>
        <% else %>
            You already like or dislike this post
        <% end %>
    <% end %>
    

    现在,让我们创建2个新的路由端点来处理喜欢和不喜欢的POST请求,如下所示:

    resources :posts do
        post 'like', on: :member, as: 'like'
        post 'dislike', on: :member, as: 'dislike'
      end
    

    现在,我们有2条新路线(运行rake routes):

    like_post    POST   /posts/:id/like(.:format)      posts#like
    dislike_post POST   /posts/:id/dislike(.:format)   posts#dislike
    

    因此,我们需要在帖子控制器中创建2个名为likedislike的新操作,如下所示:

    def like
        @post.post_users.create(post_id: @post.id, user_id: current_user.id, already_like_or_dislike: true)
        current_post_like = @post.like
        new_post_like = current_post_like + 1
        @post.update_attributes(like: new_post_like)
        redirect_to @post
      end
    
      def dislike
        @post.post_users.create(post_id: @post.id, user_id: current_user.id, already_like_or_dislike: true)
        current_post_dislike = @post.dislike
        new_post_dislike = current_post_dislike + 1
        @post.update_attributes(dislike: new_post_dislike)
        redirect_to @post
      end
    

    让我解释like行动中发生的事情。

    首先,我们在post_users表中创建一条记录,传递当前用户ID和帖子ID。并且,对于already_like_or_dislike,我们将其从默认false更改为true

    接下来,我们将该帖子的like列从当前值更新为加一(+1)值。例如,从01

    接下来,我们将重定向回显示模板。

    对于dislike行动,它非常相似。不同之处在于,我们更新了dislike表中的posts列,而不是like列。

    这就是全部。

    对于newcreate行动,它现在有点不同了:

    def new
        @post = current_user.posts.new
      end
    
    def create
        @post = current_user.posts.new(post_params)
    
        ...
      end
    

    由于我们将用户has_many :posts和帖子属于用户关联,我们只需从用户对象(Post)初始化.new current_user实例。

    执行此操作会自动添加user_id: 1,例如我们创建Post记录时,我们不需要在表单内创建隐藏字段,并使值等于当前签名-in用户ID。

    你可以check full source code of this little app here inside my Github repo

    演示结果视频:https://youtu.be/iHp_tIRzrPo