我正在研究我的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
答案 0 :(得分:1)
您考虑使用某些库吗?有一个宝石'act_as_votable',它完全符合您的要求。而且记录非常好。以下是github上的repo链接以及有关已注册投票的文档https://github.com/ryanto/acts_as_votable#registered-votes
答案 1 :(得分:1)
如果我理解你的问题,你有3个模特;用户,邮政和邮政用户。
并且,你想:
like
表格中为该帖子添加dislike
或posts
值好的,这是解决这种情况的解决方案。
<强> 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个新动作:like
和dislike
:
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.id
和user_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个名为like
和dislike
的新操作,如下所示:
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)值。例如,从0
到1
。
接下来,我们将重定向回显示模板。
对于dislike
行动,它非常相似。不同之处在于,我们更新了dislike
表中的posts
列,而不是like
列。
这就是全部。
对于new
和create
行动,它现在有点不同了:
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