如何在 RoR 中实现转发功能?
How to implement retweet functionality in RoR?
我正在尝试在我的应用程序上实现转推功能。
所以我的推文模型中有我的 retweet_id
推文架构
| user_id | content | created_at | updated_at | retweet_id
tweets.rb
belongs_to :user
has_many :retweets, class_name: 'Tweet', foreign_key: 'retweet_id'
user.rb
has_many :tweets
在我的推文控制器中
tweets_controller.rb
...
def retweet
@retweet = Tweet.new(retweet_params)
if @retweet.save
redirect_to tweet_path, alert: 'Retweeted!'
else
redirect_to root_path, alert: 'Can not retweet'
end
end
Private
...
def retweet_params
params.require(:retweet).permit(:retweet_id, :content).merge(user_id: current_user.id)
end
在我看来
tweets/show.html.erb
<%= link_to 'Retweet', retweet_tweet_path(@tweet.id), method: :post %>
我的路线
resources :tweets do
resources :comments
resources :likes
member do
post :retweet
end
end
所以当我尝试这个时我得到了一个错误
param is missing or the value is empty: retweet
所以我从 'retweet_params' 中删除了 .require 并删除了那个错误(虽然我不确定这是多么明智)
然后 link 可以工作但不会转发 - 恢复到我的操作中指定的后备 root_path。
Unpermitted parameters: :_method, :authenticity_token, :id
Redirected to http://localhost:3000/
我不确定我做错了什么。我怎样才能让我的转发工作?泰
现在您看到的错误是 Rails 中的强参数错误。如果您可以检查您的调试器或正在发送的 HTTP post 请求,您会发现您没有 retweet_params
中“需要”的参数
def retweet_params
params.require(:retweet).permit(:retweet_id, :content).merge(user_id: current_user.id)
end
这实质上是说您期望像这样的参数嵌套哈希
params = { retweet: { id: 1, content: 'Tweet' } }
这行不通,因为您只是发送 ID。改用这样的东西怎么样?
TweetsController.rb
class TweetsController < ApplicationController
def retweet
original_tweet = Tweet.find(params[:id])
@retweet = Tweet.new(
user_id: current_user.id,
content: original_tweet.content
)
if @retweet.save
redirect_to tweet_path, alert: 'Retweeted!'
else
redirect_to root_path, alert: 'Can not retweet'
end
end
end
retweet_params
引发错误的原因是您的 link link_to 'Retweet', retweet_tweet_path(@tweet.id), method: :post
不像新表单或编辑表单那样包含参数。相反,您应该创建一条新推文,引用您要转发的推文。
before_action :set_tweet, only: %i[show edit update destroy retweet]
def retweet
retweet = @tweet.retweets.build(user: current_user)
if retweet.save
redirect_to retweet, notice: 'Retweeted!'
else
redirect_to root_path, alert: 'Can not retweet'
end
end
private
def set_tweet
@tweet = Tweet.find(params[:id])
end
以上应该会自动link 将新推文发送给“父级”。如果由于某种原因这不起作用,您可以通过将上面的内容更改为:
来手动设置它
retrweet = Tweet.new(retweet_id: @tweet.id, user: current_user)
上述方法不保存任何内容,因为这是转推。
如果您不想允许同一用户多次转发同一条推文,请确保您设置了适当的约束和验证。
# migration
add_index :tweets, %i[user_id retweet_id], unique: true
# model
validates :retweet_id, uniqueness: { scope: :user_id }
我们如何访问转推的内容?答案是我们从父级或源中获取内容(无论你想怎么称呼它)。
目前没有允许您访问父推文或源推文的关联。您目前已经拥有:
has_many :retweets, class_name: 'Tweet', foreign_key: 'retweet_id'
为了轻松访问源内容,让我们先添加一个额外的关联。
belongs_to :source_tweet, optional: true, inverse_of: :retweets, class_name: 'Tweet', foreign_key: 'retweet_id'
has_many :retweets, inverse_of: :source_tweet, class_name: 'Tweet', foreign_key: 'retweet_id'
通过设置上述关联,我们可以覆盖 Tweet
模型的 content
getter 和 setter。
def content
if source_tweet
source_tweet.content
else
super
end
end
def content=(content)
if source_tweet
raise 'retweets cannot have content'
else
super
end
end
# depending on preference the setter could also be written as validation
validates :content, absence: true, if: :source_tweet
请注意,上述在谈论查询速度时效率不高,但这是最简单最清晰的解决方案。解决 parent/child 查询非常困难,如果速度成为问题,它应该有自己的问题。
如果您想知道我为什么设置 inverse_of
选项。我建议您查看 Active Record Associations - 3.5 Bi-directional Associations.
部分
我正在尝试在我的应用程序上实现转推功能。
所以我的推文模型中有我的 retweet_id
推文架构
| user_id | content | created_at | updated_at | retweet_id
tweets.rb
belongs_to :user
has_many :retweets, class_name: 'Tweet', foreign_key: 'retweet_id'
user.rb
has_many :tweets
在我的推文控制器中
tweets_controller.rb
...
def retweet
@retweet = Tweet.new(retweet_params)
if @retweet.save
redirect_to tweet_path, alert: 'Retweeted!'
else
redirect_to root_path, alert: 'Can not retweet'
end
end
Private
...
def retweet_params
params.require(:retweet).permit(:retweet_id, :content).merge(user_id: current_user.id)
end
在我看来
tweets/show.html.erb
<%= link_to 'Retweet', retweet_tweet_path(@tweet.id), method: :post %>
我的路线
resources :tweets do
resources :comments
resources :likes
member do
post :retweet
end
end
所以当我尝试这个时我得到了一个错误
param is missing or the value is empty: retweet
所以我从 'retweet_params' 中删除了 .require 并删除了那个错误(虽然我不确定这是多么明智)
然后 link 可以工作但不会转发 - 恢复到我的操作中指定的后备 root_path。
Unpermitted parameters: :_method, :authenticity_token, :id
Redirected to http://localhost:3000/
我不确定我做错了什么。我怎样才能让我的转发工作?泰
现在您看到的错误是 Rails 中的强参数错误。如果您可以检查您的调试器或正在发送的 HTTP post 请求,您会发现您没有 retweet_params
def retweet_params
params.require(:retweet).permit(:retweet_id, :content).merge(user_id: current_user.id)
end
这实质上是说您期望像这样的参数嵌套哈希
params = { retweet: { id: 1, content: 'Tweet' } }
这行不通,因为您只是发送 ID。改用这样的东西怎么样?
TweetsController.rb
class TweetsController < ApplicationController
def retweet
original_tweet = Tweet.find(params[:id])
@retweet = Tweet.new(
user_id: current_user.id,
content: original_tweet.content
)
if @retweet.save
redirect_to tweet_path, alert: 'Retweeted!'
else
redirect_to root_path, alert: 'Can not retweet'
end
end
end
retweet_params
引发错误的原因是您的 link link_to 'Retweet', retweet_tweet_path(@tweet.id), method: :post
不像新表单或编辑表单那样包含参数。相反,您应该创建一条新推文,引用您要转发的推文。
before_action :set_tweet, only: %i[show edit update destroy retweet]
def retweet
retweet = @tweet.retweets.build(user: current_user)
if retweet.save
redirect_to retweet, notice: 'Retweeted!'
else
redirect_to root_path, alert: 'Can not retweet'
end
end
private
def set_tweet
@tweet = Tweet.find(params[:id])
end
以上应该会自动link 将新推文发送给“父级”。如果由于某种原因这不起作用,您可以通过将上面的内容更改为:
来手动设置它retrweet = Tweet.new(retweet_id: @tweet.id, user: current_user)
上述方法不保存任何内容,因为这是转推。
如果您不想允许同一用户多次转发同一条推文,请确保您设置了适当的约束和验证。
# migration
add_index :tweets, %i[user_id retweet_id], unique: true
# model
validates :retweet_id, uniqueness: { scope: :user_id }
我们如何访问转推的内容?答案是我们从父级或源中获取内容(无论你想怎么称呼它)。
目前没有允许您访问父推文或源推文的关联。您目前已经拥有:
has_many :retweets, class_name: 'Tweet', foreign_key: 'retweet_id'
为了轻松访问源内容,让我们先添加一个额外的关联。
belongs_to :source_tweet, optional: true, inverse_of: :retweets, class_name: 'Tweet', foreign_key: 'retweet_id'
has_many :retweets, inverse_of: :source_tweet, class_name: 'Tweet', foreign_key: 'retweet_id'
通过设置上述关联,我们可以覆盖 Tweet
模型的 content
getter 和 setter。
def content
if source_tweet
source_tweet.content
else
super
end
end
def content=(content)
if source_tweet
raise 'retweets cannot have content'
else
super
end
end
# depending on preference the setter could also be written as validation
validates :content, absence: true, if: :source_tweet
请注意,上述在谈论查询速度时效率不高,但这是最简单最清晰的解决方案。解决 parent/child 查询非常困难,如果速度成为问题,它应该有自己的问题。
如果您想知道我为什么设置 inverse_of
选项。我建议您查看 Active Record Associations - 3.5 Bi-directional Associations.